一周掌握FPGA Verilog HDL语法 day 2_fpga scalared 型wire-程序员宅基地

技术标签: Verilog HDL语法  fpga  FPGA学习系列  

一周掌握FPGA Verilog HDL语法 day 2

今天给大侠带来的是一周掌握FPGA Verilog HDL 语法,今天开启第二天。上一篇提到了整数型以及参数型,此篇我们继续来看变量以及后续其他内容,结合实例理解理论语法,会让你理解运用的更加透彻。下面咱们废话就不多说了,一起来看看吧。

 

变量

变量即在程序运行过程中其值可以改变的量,在Verilog HDL中变量的数据类型有很多种,这里只对常用的几种进行介绍。

网络数据类型表示结构实体(例如门)之间的物理连接。网络类型的变量不能储存值,而且它必须受到驱动器(例如门或连续赋值语句,assign)的驱动。如果没有驱动器连接到网络类型的变量上,则该变量就是高阻的,即其值为z。

常用的网络数据类型包括wire型和tri型。这两种变量都是用于连接器件单元,它们具有相同的语法格式和功能。之所以提供这两种名字来表达相同的概念是为了与模型中所使用的变量的实际情况相一致。wire型变量通常是用来表示单个门驱动或连续赋值语句驱动的网络型数据,tri型变量则用来表示多驱动器驱动的网络型数据。如果wire型或tri型变量没有定义逻辑强度(logic strength),在多驱动源的情况下,逻辑值会发生冲突从而产生不确定值。下表为wire型和tri型变量的真值表(注意:这里假设两个驱动源的强度是一致的,关于逻辑强度建模请自行查阅相关资料)

 

一. wire型

wire型数据常用来表示用于以assign关键字指定的组合逻辑信号。Verilog程序模块中输入输出信号类型缺省时自动定义为wire型。wire型信号可以用作任何方程式的输入,也可以用作“assign”语句或实例元件的输出。

wire型信号的格式同reg型信号的很类似。

其格式如下: wire [n-1:0] 数据名1,数据名2,…数据名i; //共有i条总线,每条总线内有n条线路 或 wire [n:1] 数据名1,数据名2,…数据名i;

wire是wire型数据的确认符,[n-1:0]和[n:1]代表该数据的位宽,即该数据有几位。最后跟着的是数据的名字。如果一次定义多个数据,数据名之间用逗号隔开。声明语句的最后要用分号表示语句结束。看下面的几个例子。


wire a; //定义了一个一位的wire型数据 
wire [7:0] b; //定义了一个八位的wire型数据 
wire [4:1] c, d; //定义了二个四位的wire型数据

二. reg型

寄存器是数据储存单元的抽象。寄存器数据类型的关键字是reg.通过赋值语句可以改变寄存器储存的值,其作用与改变触发器储存的值相当。Verilog HDL语言提供了功能强大的结构语句使设计者能有效地控制是否执行这些赋值语句。这些控制结构用来描述硬件触发条件,例如时钟的上升沿和多路器的选通信号。在行为模块介绍这一节中我们还要详细地介绍这些控制结构。reg类型数据的缺省初始值为不定值,x。

reg型数据常用来表示用于“always”模块内的指定信号,常代表触发器。通常,在设计中要由“always”块通过使用行为描述语句来表达逻辑关系。在“always”块内被赋值的每一个信号都必须定义成reg型。reg型数据的格式如下:

reg [n-1:0] 数据名1,数据名2,… 数据名i; 或 reg [n:1] 数据名1,数据名2,… 数据名i;

reg是reg型数据的确认标识符,[n-1:0]和[n:1]代表该数据的位宽,即该数据有几位(bit)。最后跟着的是数据的名字。如果一次定义多个数据,数据名之间用逗号隔开。声明语句的最后要用分号表示语句结束。看下面的几个例子:


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

对于reg型数据,其赋值语句的作用就像改变一组触发器的存储单元的值。在Verilog中有许多构造(construct)用来控制何时或是否执行这些赋值语句。这些控制构造可用来描述硬件触发器的各种具体情况,如触发条件用时钟的上升沿等,或用来描述具体判断逻辑的细节,如各种多路选择器。reg型数据的缺省初始值是不定值。reg型数据可以赋正值,也可以赋负值。但当一个reg型数据是一个表达式中的操作数时,它的值被当作是无符号值,即正值。例如:当一个四位的寄存器用作表达式中的操作数时,如果开始寄存器被赋以值-1,则在表达式中进行运算时,其值被认为是+15。

注意:

reg型只表示被定义的信号将用在“always”块内,理解这一点很重要。并不是说reg型信号一定是寄存器或触发器的输出。虽然reg型信号常常是寄存器或触发器的输出,但并不一定总是这样。在本书中我们还会对这一点作更详细的解释。

 

三. memory型

Verilog HDL通过对reg型变量建立数组来对存储器建模,可以描述RAM型存储器,ROM存储器和reg文件。数组中的每一个单元通过一个数组索引进行寻址。在Verilog语言中没有多维数组存在。memory型数据是通过扩展reg型数据的地址范围来生成的。其格式如下:

reg [n-1:0] 存储器名[m-1:0];或 reg [n-1:0] 存储器名[m:1];

在这里,reg[n-1:0]定义了存储器中每一个存储单元的大小,即该存储单元是一个n位的寄存器。存储器名后的[m-1:0]或[m:1]则定义了该存储器中有多少个这样的寄存器。最后用分号结束定义语句。下面举例说明:

reg [7:0] mema[255:0];

这个例子定义了一个名为mema的存储器,该存储器有256个8位的存储器。该存储器的地址范围是0到255。

注意:对存储器进行地址索引的表达式必须是常数表达式。

另外,在同一个数据类型声明语句里,可以同时定义存储器型数据和reg型数据。见下例:

 

parameter wordsize=16, //定义二个参数。 
         memsize=256;         
reg [wordsize-1:0] mem[memsize-1:0],writereg, readreg;

 

尽管memory型数据和reg型数据的定义格式很相似,但要注意其不同之处。如一个由n个1位寄存器构成的存储器组是不同于一个n位的寄存器的。见下例:

 

reg [n-1:0] rega; //一个n位的寄存器 
reg mema [n-1:0]; //一个由n个1位寄存器构成的存储器组

 

一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。见下例:

rega =0; //合法赋值语句

mema =0; //非法赋值语句

如果想对memory中的存储单元进行读写操作,必须指定该单元在存储器中的地址。下面的写法是正确的。

mema[3]=0; //给memory中的第3个存储单元赋值为0。

进行寻址的地址索引可以是表达式,这样就可以对存储器中的不同单元进行操作。表达式的值可以取决于电路中其它的寄存器的值。例如可以用一个加法计数器来做RAM的地址索引。本篇只对以上几种常用的数据类型和常数进行了介绍,其余的在以后使用到时再逐一介绍。有兴趣的大侠可以自行查阅资料进行修炼。

 

运算符及表达式

Verilog HDL语言的运算符范围很广,其运算符按其功能可分为以下几类:

  1. 算术运算符(+,-,×,/,%)

  2. 赋值运算符(=,<=)

  3. 关系运算符(>,<,>=,<=)

  4. 逻辑运算符(&&,||,!)

  5. 条件运算符(?:)

  6. 位运算符(~,|,^,&,^~)

  7. 移位运算符(<<,>>)

  8. 拼接运算符({ })

  9. 其它

在Verilog HDL语言中运算符所带的操作数是不同的,按其所带操作数的个数运算符可分为三种:

  1. 单目运算符(unary operator):可以带一个操作数,操作数放在运算符的右边。

  2. 二目运算符(binary operator):可以带二个操作数,操作数放在运算符的两边。

  3. 三目运算符(ternary operator):可以带三个操作,这三个操作数用三目运算符分隔开。 见下例: clock = ~clock; // ~是一个单目取反运算符, clock是操作数。 c = a | b; // 是一个二目按位或运算符, a 和 b是操作数。 r = s ? t : u; // ?: 是一个三目条件运算符, s,t,u是操作数。

下面对常用的几种运算符进行介绍。

 

基本的算术运算符

在Verilog HDL语言中,算术运算符又称为二进制运算符,共有下面几种:

  1. + (加法运算符,或正值运算符,如 rega+regb,+3)

  2. - (减法运算符,或负值运算符,如 rega-3,-3)

  3. × (乘法运算符,如rega*3)

  4. / (除法运算符,如5/3)

  5. % (模运算符,或称为求余运算符,要求%两侧均为整型数据。如7%3的值为1)

在进行整数除法运算时,结果值要略去小数部分,只取整数部分。而进行取模运算时,结果值的符号位采用模运算式里第一个操作数的符号位。见下例。

注意:在进行算术运算操作时,如果某一个操作数有不确定的值x,则整个结果也为不定值x。

 

位运算符

Verilog HDL作为一种硬件描述语言,是针对硬件电路而言的。在硬件电路中信号有四种状态值1,0,x,z。在电路中信号进行与或非时,反映在Verilog HDL中则是相应的操作数的位运算。Verilog HDL提供了以下五种位运算符:

  1. ~ //取反

  2. & //按位与

  3. | //按位或

  4. ^ //按位异或

  5. ^~ //按位同或(异或非)

说明:

位运算符中除了~是单目运算符以外,均为二目运算符,即要求运算符两侧各有一个操作数.

位运算符中的二目运算符要求对两个操作数的相应位进行运算操作。

下面对各运算符分别进行介绍:

  1. "取反"运算符~

~是一个单目运算符,用来对一个操作数进行按位取反运算。其运算规则见下表:

举例说明:

 
rega='b1010;//rega的初值为'b1010 
rega=~rega;//rega的值进行取反运算后变为'b0101

 

  1. "按位与"运算符&

按位与运算就是将两个操作数的相应位进行与运算, 其运算规则见下表:

  1. "按位或"运算符|

按位或运算就是将两个操作数的相应位进行或运算。其运算规则见下表:

  1. "按位异或"运算符^(也称之为XOR运算符)

按位异或运算就是将两个操作数的相应位进行异或运算。其运算规则见下表:

  1. "按位同或"运算符^~

按位同或运算就是将两个操作数的相应位先进行异或运算再进行非运算. 其运算规则见下表:

  1. 不同长度的数据进行位运算

两个长度不同的数据进行位运算时,系统会自动的将两者按右端对齐.位数少的操作数会在相应的高位用0填满,以使两个操作数按位进行操作。

 

逻辑运算符

在Verilog HDL语言中存在三种逻辑运算符:

  1. && 逻辑与

  2. || 逻辑或

  3. ! 逻辑非

"&&"和"||"是二目运算符,它要求有两个操作数,如(a>b)&&(b>c),(a<b)||(b<c)。"!"是单目运算符,只要求一个操作数,如!(a>b)。下表为逻辑运算的真值表。它表示当a和b的值为不同的组合时,各种逻辑运算所得到的值。

逻辑运算符中"&&"和"||"的优先级别低于关系运算符,"!" 高于算术运算符。见下例:

(a>b)&&(x>y) 可写成: a>b && x>y

(a==b)||(x==y) 可写成:a==b || x==y

(!a)||(a>b) 可写成: !a || a>b

为了提高程序的可读性,明确表达各运算符间的优先关系,建议使用括号。

 

关系运算符

关系运算符共有以下四种:

a < b a小于b

a > b a大于b

a <= b a小于或等于b

a >= b a大于或等于b

在进行关系运算时,如果声明的关系是假的(flase),则返回值是0,如果声明的关系是真的(true),则返回值是1,如果某个操作数的值不定,则关系是模糊的,返回值是不定值。

所有的关系运算符有着相同的优先级别。关系运算符的优先级别低于算术运算符的优先级别。见下例:

a < size-1 //这种表达方式等同于下面

a < (size-1) //这种表达方式。

size - ( 1 < a ) //这种表达方式不等同于下面

size - 1 < a //这种表达方式。

从上面的例子可以看出这两种不同运算符的优先级别。当表达式size-(1<a)进行运算时,关系表达式先被运算,然后返回结果值0或1被size减去。而当表达式 size-1<a 进行运算时,size先被减去1,然后再同a相比。

 

等式运算符

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

  1. == (等于)

  2. != (不等于)

  3. === (等于)

  4. !== (不等于)

这四个运算符都是二目运算符,它要求有两个操作数。"=="和"!="又称为逻辑等式运算符。其结果由两个操作数的值决定。由于操作数中某些位可能是不定值x和高阻值z,结果可能为不定值x。而"==="和"!=="运算符则不同,它在对操作数进行比较时对某些位的不定值x和高阻值z也进行比较,两个操作数必需完全一致,其结果才是1,否则为0。"==="和"!=="运算符常用于case表达式的判别,所以又称为"case等式运算符"。这四个等式运算符的优先级别是相同的。下面画出==与===的真值表,帮助理解两者间的区别。

下面举一个例子说明“==”和“===”的区别。例:

if(A==1’bx) $display(“AisX”); (当A等于X时,这个语句不执行)

if(A===1’bx) $display(“AisX”); (当A等于X时,这个语句执行)

 

移位运算符

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

<< (左移位运算符) 和 >>(右移位运算符)。

其使用方法如下:a >> n 或 a << n

a代表要进行移位的操作数,n代表要移几位。这两种移位运算都用0来填补移出的空位。下面举例说明:

 
module shift;

  reg [3:0] start, result; 
  
    initial 
      begin 
        start = 1;  //start在初始时刻设为值0001 
        result = (start<<2); //移位后,start的值0100,然后赋给result。 
      end 
      
endmodule

 

从上面的例子可以看出,start在移过两位以后,用0来填补空出的位。进行移位运算时应注意移位前后变量的位数,下面将给出一例。

例:4’b1001<<1 = 5’b10010; 4’b1001<<2 = 6’b100100; 1<<6 = 32’b1000000; 4’b1001>>1 = 4’b0100; 4’b1001>>4 = 4’b0000;

 

位拼接运算符(Concatation)

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

{信号1的某几位,信号2的某几位,..,..,信号n的某几位}

即把某些信号的某些位详细地列出来,中间用逗号分开,最后用大括号括起来表示一个整体信号。见下例:

{a,b[3:0],w,3’b101} 也可以写成为 {a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1}

在位拼接表达式中不允许存在没有指明位数的信号。这是因为在计算拼接信号的位宽的大小时必须知道其中每个信号的位宽。位拼接还可以用重复法来简化表达式。见下例:

{4{w}} //这等同于{w,w,w,w} 位拼接还可以用嵌套的方式来表达。

见下例:{b,{3{a,b}}} //这等同于{b,a,b,a,b,a,b} 用于表示重复的表达式如上例中的4和3,必须是常数表达式。

 

缩减运算符(reduction operator)

缩减运算符是单目运算符,也有与或非运算。其与或非运算规则类似于位运算符的与或非运算规则,但其运算过程不同。位运算是对操作数的相应位进行与或非运算,操作数是几位数则运算结果也是几位数。而缩减运算则不同,缩减运算是对单个操作数进行或与非递推运算,最后的运算结果是一位的二进制数。缩减运算的具体运算过程是这样的:第一步先将操作数的第一位与第二位进行或与非运算,第二步将运算结果与第三位进行或与非运算,依次类推,直至最后一位。

例如:reg [3:0] B; reg C; C = &B; 相当于:C =( (B[0]&B[1]) & B[2] ) & B[3];

由于缩减运算的与、或、非运算规则类似于位运算符与、或、非运算规则,这里不再详细讲述,请参照位运算符的运算规则介绍。

 

优先级别

下面对各种运算符的优先级别关系作一总结。见下表:

 

关键词

在Verilog HDL中,所有的关键词是事先定义好的确认符,用来组织语言结构。关键词是用小写字母定义的,因此在编写原程序时要注意关键词的书写,以避免出错。下面是Verilog HDL中使用的关键词(请参阅附录:Verilog语言参考手册):always, and, assign,begin,buf,bufif0,bufif1,case,casex,casez,cmos,deassign,default,defparam,disable,edge,else,end,endcase,endmodule,endfunction,endprimitive, endspecify, endtable, endtask, event, for, force, forever, fork, function,highz0,highz1, if,initial, inout, input,integer,join,large,macromodule,medium,module,nand,negedge,nmos,nor,not,notif0,notifl, or, output, parameter, pmos, posedge, primitive, pull0, pull1, pullup, pulldown, rcmos, reg, releses, repeat, mmos, rpmos, rtran, rtranif0,rtranif1,scalared,small,specify,specparam,strength,strong0, strong1, supply0, supply1, table, task, time, tran, tranif0, tranif1, tri, tri0, tri1, triand, trior, trireg,vectored,wait,wand,weak0,weak1,while, wire,wor, xnor, xor 。

注意在编写Verilog HDL程序时,变量的定义不要与这些关键词冲突。

Day 2 就到这里,Day 3 继续开始赋值语句和块语句。

 

【QQ交流群】

群号:173560979,进群暗语:FPGA技术江湖粉丝。

多年的FPGA企业开发经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有1000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有。

 

【微信交流群】

现微信交流群已建立08群,人数已达数千人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_40310273/article/details/112856607

智能推荐

基于opencv的人脸检测与识别(python)(1)-程序员宅基地

文章浏览阅读514次。基于opencv的人脸检测,再使用tensorflow的框架以及keras库通过卷积神经网络对获取的人脸数据进行训练,生成训练模型,并对实时图片进行人脸识别。

Numbers on Tree_k. numbers on tree-程序员宅基地

文章浏览阅读160次。D. Numbers on Treetime limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutputstandard outputEvlampiy was gifted a rooted tree. The vertices of the tree are numbered..._k. numbers on tree

软件测试工程师面试题-测试概念篇_面试测试工程师概念性问题有哪些-程序员宅基地

文章浏览阅读901次。转载于:https://www.cnblogs.com/mrwuzs/p/7976534.html_面试测试工程师概念性问题有哪些

0910-12学习记录-OFDM细节描述_ofdm子载波流数-程序员宅基地

文章浏览阅读899次。PPDU编码过程总览编码过程包含了很多细节的步骤,在以下的细节条款有很详细的描述。接下来的总览主要是为了促进对于这些细节的理解。生成PLCP前导码字段,包含10个短训练序列(用来做AGC增益控制,分集选择,时间的同步获取以及在接收端的粗频偏估计)和两个重复的长训练序列(用来做信道估计以及接收端的精准频偏估计)前面有保护间隔(GI)。具体的细节描述在 17.3.3.17.3.3.描述PLCP..._ofdm子载波流数

OSChina 中秋节乱弹 ——加班比抢了我的小鱼干,更让我难过!-程序员宅基地

文章浏览阅读234次。2019独角兽企业重金招聘Python工程师标准>>> ...

SpringBoot引入MyBatis_springboot mybatis jar maven引入-程序员宅基地

文章浏览阅读128次。首先进入spring官网,添加依赖,然后生成项目。打开Idea,然后导入刚才生成的项目文件。测试不用集成组件,要不然下载会下载很长时间。找到maven插件,导入必要的jar包。_springboot mybatis jar maven引入

随便推点

Shell根据文本内容批量修改文件名(附完整代码)_linux shell while批量改名-程序员宅基地

文章浏览阅读3.1k次。Shell根据文本内容批量修改文件名_linux shell while批量改名

“计算机系统概述”学习笔记_程序计数器怎么计算下一条指令的地址-程序员宅基地

文章浏览阅读2.2k次。文章目录机器字长存储器组成运算器组成控制器组成计算机系统的层次结构指令执行过程源程序翻译成可执行文件的过程机器字长计算机进行一次整数运算所能处理的二进制数据的位数。存储器组成组件由大到小(大包含小)依次为:计算机系统=计算机硬件系统+计算机软件系统计算机硬件系统=存储器+控制器+运算器+输入设备+输出设备存储器=主存储器(内存储器)+辅助存储器(外存储器)主存储器=地址寄存器(MAR)+存储体+数据寄存器(MDR)+时序控制逻辑存储体=若干存储单元存储单元=若干存储元件每个存储元件存_程序计数器怎么计算下一条指令的地址

Scala编写JedisPoolUtils工具类_jedis scala-程序员宅基地

文章浏览阅读1.5k次。package com.cloudera.utilsimport redis.clients.jedis.{Jedis, JedisPool, JedisPoolConfig}object JedisPoolUtils extends Serializable { @transient private var pool: JedisPool = null def makePoo..._jedis scala

MySQL 使用AVG聚合函数时,保留两位小数的方法_mysql avg保留两位小数-程序员宅基地

文章浏览阅读3.1k次。SELECT ( CASE WHEN platform_parameter IS NULL THEN page ELSE platform_parameter END ) AS page, sum(pv) AS pv, sum(uv) AS uv, CAST(AVG(time) AS DECIMAL(10,2)) as timeFROM t_page_stat_daily tLEFT JOIN t_app_dictionary d ON t.app_id = d._mysql avg保留两位小数

QOS_qos双色分离-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏9次。QOS按权重进行资源分配,进行资源协调(1) 甄别流量(哪些有用,哪些无用----重要程度)(2) 分析流量诉求(有哪些要求----带宽、时延)(3) 细化流量诉求(对哪些参数比较敏感)队列机制 拥塞避免一、 流量分类TOS位,位于包头为之后,8位二进制规定:数字越大,越容易从接口出去(优先级越高)不合理之处:当队列满时,若再有较重要流量要进行排队,将会被拒绝DSCP:插分..._qos双色分离

聚类算法系列---DBSCAN密度聚类算法_聚类公式 ci min y dbscan-程序员宅基地

文章浏览阅读430次。DBSCAN(Density-Based Spatial Clustering of Application with Noise)思想:用一个点的邻域内的邻居点数来衡量该店所在的空间密度,根据密度来判定将样本划分到哪个簇,对于同一个簇里面的样本是紧密相连的。在进行聚类的时候事先不知道cluster的数目。基本概念设数据集X={x1,x2,....,xn}Eps:定义密度时的邻域半径..._聚类公式 ci min y dbscan

推荐文章

热门文章

相关标签