Verilog入门教程与实例分享

本文目录

前言

一、Verilog入门教程

1.基础语法

2.数值表示

3.数据类型

4.表达式

5.编译指令

6.过程结构

7.过程赋值

8.语句块

9.连续赋值语句

10.延时语句

11.时序控制

12.条件语句

13.多路分支语句

14.循环语句

15.过程连续赋值

16.数值转换

二、Verilog实例分享

1.计算数据位数

2.多次判断

3.循环计数

4.捕捉上升下降沿

总结

前言

本文记录了Verilog语言的入门基础知识,并通过一些代码实例帮助大家上手,主要基于XilinxVivado完成,以下个人学习经验仅供参考。

一、Verilog入门教程

1.基础语法

(1)关键字必须小写,如reg、input

(2)标识符区分大小写,开头必须是字母或下划线,如CLK、clk(两者不同)

(3)每行必须以;结束

(4)单行注释用//xxx,跨行注释用/*xxx*/

2.数值表示

(1)基本数值种类:0(0或假)、1(1或真)、x/X(未知)、z/Z(高阻)

(2)整数基数格式:二进制('b或'B),八进制('o或'O),十进制('d或'D),十六进制('h或'H)

(3)整数表示方法:4’b1001(指明位宽,4位二进制“1001”)或100(不指明位宽,默认十进制“100”)

(4)负数表示方法:-4’b1001(指明位宽时)或-100(不指明位宽时)

(5)实数表示方法:十进制(0.001)或科学记数法(1.2e4)

(6)字符串表示方法:需要定义相应大小的存储单元,比如字符串""需要12*8bit的存储单元,代码如下:

reg[12*8-1:0]str;

assignstr="";

1

2

3.数据类型

(1)线网:wire,表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动

(2)寄存器:reg,表示存储单元,它会保持数据原有的值直到被改写

(3)向量:当位宽大于1时线网或寄存器即可表示向量,举例如下:

wire[8-1:0]addr;

reg[8-1:0]addr_temp;

addr_temp[7:6]=addr[1:0]+1'b1;

1

2

3

(7)数组:数组中的每个元素都可视为一个标量或者向量,形如数组名字[位数],举例如下:

integerflag[7:0];//8个整数组成的数组flag

reg[3:0]counter[3:0];//4个4位reg型变量组成的数组counter

wire[7:0]addr[3:0];//4个8位wire型变量组成的数组addr

flag[1]=32'd0;//将flag中第2个元素赋值为32位的0值

counter[3]=4'hF;//将counter中第4个元素赋值为4位的十六进制数F

assignaddr[0]=8'b0;//将addr中第1个元素赋值为0

1

2

3

4

5

6

4.表达式

(1)表达式:由操作符和操作数构成,目的是根据操作符的意义得到一个计算结果

(2)操作数:可以是任意数据类型,如常数、整数、实数、线网、寄存器、时间、函数等

(3)操作符:包括算术、关系、等价、逻辑、按位、归约、移位、拼接、条件操作符等,圆括号内表达式优先执行,同类型操作符之间除条件操作符从右往左关联,其余操作符都是自左向右关联

(4)算术操作符:包括单目操作符(“+”、“-”,表示操作数正负,优先级最高)和双目操作符(加“+”、减“-”、乘“*”、除“/”、求幂(两个星号)、取模“%”)

(5)关系操作符:大于“”、小于“”、大于等于“=”、小于等于“=”,结果为真“1”或假“0”

(6)等价操作符:逻辑相等“==”、逻辑不等“!=”、全等”===“、非全等“!==”,结果为真“1”或假“0”

(7)逻辑操作符:逻辑与“”、逻辑或“||”、逻辑非“!”

(8)按位操作符:取反“~”、与“”、或“|”、异或“^”、同或“~^”

(9)归约操作符:归约与“”、归约与非“~”、归约或“|”、归约或非“~|”、归约异或“^”、归约同或“~^”

(10)移位操作符:左移“”、右移“”、算术左移“”、算术右移“”

(11)拼接操作符:用大括号{,}表示,用于将多个操作数拼接成新的操作数,每个操作数必须指定位宽

(12)条件操作符:判断条件condition是否满足,满足执行true对应语句,不满足执行false对应语句,可嵌套执行多次判断,格式如下:

condition?true:false

1

5.编译指令

(1)宏定义编译指令(与C一致)

`define

`undef

(2)条件编译指令(与C一致)

`ifdef

`ifndef

`else

`elsif

`if

(3)`include:用于将全局或公用头文件包含在设计文件里,使用相对或绝对路径皆可

(4)`timescale:定义时间单位和时间精度,两者都是由数字和单位(s、ms、us、ns、ps、fs)组成,时间精度大小小于等于时间单位大小,举例如下:

`timescale1ns/100ps//合法

//`timescale100ps/1ns//不合法

1

2

(5)`resetall:将所有编译指令重设为缺省值

(6)单元模块定义(cell)

`celldefine

`celldefine

举例如下:

`celldefine

module(

inputclk,

inputrst,

outputA,

outputB);

module

`celldefine

1

2

3

4

5

6

7

8

6.过程结构

(1)initial语句:

initial语句从0时刻开始执行,单次执行,多个语句之间并行执行,单个语句内顺序执行;

块内包含多个语句时需要使用关键字begin和,只有一条语句时可不用

(2)always语句:

always语句从0时刻开始执行,重复执行,多个语句之间并行执行,单个语句内顺序执行;

块内包含多个语句时需要使用关键字begin和,只有一条语句时可不用

7.过程赋值

(1)阻塞赋值“=”:语句顺序执行,即下一条语句执行前当前语句一定会执行完毕

(2)非阻塞赋值“=”:语句并行执行,即其他语句的执行和当前语句的执行同时进行

8.语句块

(1)顺序块:块中语句顺序执行,但非阻塞赋值仍按并行执行,用begin表示

(2)并行块:块中语句并行执行,包括阻塞赋值,用forkjoin表示

(3)嵌套块:顺序块+并行块

moduletest;

initialbegin:A//块命名为A,disable后禁用命名块

integerB;//变量B可通过被其他模块调用

module

1

2

3

4

5

9.连续赋值语句

连续赋值语句“assign”用于对wire型变量进行赋值,格式如下:

wirez,x,y;

assignz=xy;//只要x、y改变z就会相应改变,注意z必须是wire型变量,x、y可以是wire型或reg型变量

1

2

10.延时语句

(连续赋值)延时语句“assign10z=xy;//延时10个时间单位后赋值,若信号脉冲宽度小于延时则对输出无影响,称为惯性延时

1

2

11.时序控制

(1)延时控制:包括常规延时控制与内嵌延时控制

常规延时格式为:(先延时再赋值,无惯性延时问题)

10y=x;

1

2

内嵌延时格式为:(先赋值再延时,有惯性延时问题)

y=#10x;

1

(2)事件控制:包括边沿触发事件控制与电平敏感事件控制

边沿触发事件格式为:

always@(posedgeclkornegedgerst_n)//用@表示边沿触发条件,只有当信号发生特定变化时才能继续执行语句A

begin

A;

1

2

3

4

posedge指信号边沿正向跳变时触发,negedge指信号边沿负向跳变时触发,未指明时正负边沿跳变都会触发;

用关键字or连接多个变量,当变量很多时可简写为@(*),表示对所有输入变量的边沿跳变都会触发;

eventA;

always@(posedgeclk)begin//clk上升沿作为A触发

-A;//-表示触发

always@(A)begin//A触发时执行B

B;

1

2

3

4

5

6

7

电平敏感事件格式为:

wait(x);//x为电平敏感条件,只有当电平敏感条件为真时才能继续执行语句A

begin

A;

1

2

3

4

12.条件语句

条件语句“if”用于根据条件判断是否执行相应语句,格式如下:

if(x)A;//如果满足条件x则执行A语句(若语句不只一行则应用“beginA;”格式)

elseif(y)B;//如果满足条件y则执行B语句(elseif可有多级或者没有)

elseC;//否则执行C语句

1

2

3

13.多路分支语句

多路分支语句"case"用于解决if语句中条件选项过多时使用不方便的问题,格式如下:

case(variable)

x:A;//variable=x时执行A语句(若语句不只一行则应用“beginA;”格式)

y:B;//variable=y时执行B语句(除x、y还可以有多级case)

default:Z;//default语句可没有

1

2

3

4

14.循环语句

(1)while循环语句(所有循环语句只能在“always”或“initial”块中使用)

while(x)

begin

A;//满足x条件时执行A语句,A只有一行时begin可省略

1

2

3

4

(2)for循环语句

for(x;y;z)//x为初始条件,y为终止条件,z为控制变量的过程赋值语句,注意增加或减少变量计数不能写成i++或i--

begin

A;

1

2

3

4

(3)repeat循环语句

repeat(n)//执行固定次数n个循环

begin

A;

1

2

3

4

(4)forever循环语句

forever//相当于while(1),表示永久循环,通过系统函数$finish退出

begin

A;

1

2

3

4

15.过程连续赋值

(1)assign(过程赋值)deassign(取消过程赋值):

赋值对象只能是wire型变量而不能是reg型变量,赋值过程中对寄存器连续赋值,寄存器中的值被保留直到被重新赋值

(2)force(强制赋值)release(取消强制赋值):

赋值对象可以是reg型或wire型变量;

force作用在寄存器上时,寄存器当前值被覆盖,release时该寄存器值将继续保留强制赋值时的值;

force作用在线网上时,线网当前值被覆盖,但release时该线网值马上变为原有的驱动值

16.数值转换

(1)十进制有符号数转二进制补码:

正数的补码为原码;

负数的补码有两种计算方式:

a、将有符号数最高位符号位改写为1,剩余数值部分取反加1

比如4位数字-7的数值部分为4’b0111,高位改写后为4’b1111,剩余数值部分取反加1后为4’b1001

b、将有符号数直接与其代表的最大数值范围相加

比如4位数字-7与16(2的4次幂)的和为9,即对应4’b1001

(2)二进制补码转十进制有符号数:

补码最高位为0时其数值大小即为表示的十进制正数;

补码最高位为1时有两种计算方式:

a、将补码取反加1,并增加符号位

比如4位数字-7的补码为4’b1001,取反加1后为4’b0111,增加符号位后为-7

b、将补码对应的无符号数与其代表的最大数值范围相减

比如4位数字-7的补码为4’b1001,无符号数为9,9-16=-7

(3)求二进制补码的绝对值:

将补码取反加1,比如4位数字-7的补码为4’b1001,取反加1后为4’b0111,即7

(4)符号位扩展:

将代表符号位的最高位填充至扩展的高位数据位中,比如4’b1011(-7)扩展到8位为8’b11111011(-7)

二、Verilog实例分享

1.计算数据位数

代码如下:

functionintegerlog2(inputintegern);

integeri;

for(i=0;2**i=n;i=i+1)

log2=i+1;

function

1

2

3

4

5

假设n=15(00001111),那么log2=4,也就是4位;

假设n=16(00010000),那么log2=5,也就是5位。

2.多次判断

代码如下:

regx;

x=((x==4'd0)?A:((x==4'd1)?B:((x==4'd2)?C:D)));

1

2

变量x为4’d0执行A语句,为4’d1执行B语句,为4’d2执行C语句,否则执行D语句。

3.循环计数

代码如下:

(*mark_debug="true"*)reg[5:0]CNT;

always@(posedgeCLKornegedgeRST)

begin

if(!RST)

CNT=1'b0;

else

CNT=(CNT==最大计数-1)?1'd0:CNT+1'd1;

1

2

3

4

5

6

7

8

“最大计数”位置应给定一个值,CNT将在0~最大计数区间内循环+1。注意第一句(mark_debug=“true”)表示监视该变量。

4.捕捉上升下降沿

代码如下:

regtriger,triger_dly1,triger_dly2;

always@(posedgeCLKornegedgeRST)

begin

if(!RST)

begin

triger_dly1=1'b0;

triger_dly2=1'b0;

else

begin

triger_dly1=triger;

triger_dly2=triger_dly1;

wireposedge_triger=triger_dly1(~triger_dly2);

wirenegedge_triger=(~triger_dly1)triger_dly2;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

对triger延时1拍和2拍产生triger_dly1和triger_dly2变量,triger_dly1为上升沿时通过posedge_triger捕捉,triger_dly2为下降沿时通过negedge_triger捕捉。

总结

如果文章中有错误或疏漏之处烦请指正,希望大家多交流共同进步!

版权声明:本站所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请举报,一经查实,本站将立刻删除。

相关推荐