当前位置:   article > 正文

Verilog语法

verilog语法

Verilog语法


一、Verilog设计方法

Verilog的设计多采用自上而下的设计方法(top-down)。即先定义顶层模块功能,进而分析要构成顶层模块的必要子模块;然后进一步对各个模块进行分解、设计,直到到达无法进一步分解的底层功能模块。
在这里插入图片描述
设计流程:
在这里插入图片描述


二、模块的结构

1.模块端口定义

Verilog的基本设计单元是模块(block)。一个模块是由两部分组成的,一部分描述接口,另一部分描述逻辑功能,即定义输入是如何影响输出的。
程序模块

module block (a,b,c,d);//声明了模块的输入输出
input a,b;
output c,d;
assign c = a | b;
assign d = a & b;
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

电路图符号
在这里插入图片描述

2.模块内容

I/O的格式

输入口:
input [信号位宽-1:0] 端口名1;
输出口:
output [信号位宽-1:0] 端口名1
  • 1
  • 2
  • 3
  • 4

内部信号说明:
在模块内用到的和端口有关的wire和reg类型变量的声明。

reg[width-1:0] R变量1,R变量2;
wire[width-1:0] W变量1,W变量2
  • 1
  • 2

时延:
连续赋值延时语句中的延时,用于控制任意操作数发生变化到语句左端赋予新值之间的时间延时。时延一般是不可综合的。

//普通时延,A&B计算结果延时10个时间单位赋值给Z
wire Z,A,B;
assign #10 Z = A & B;
//隐式时延,声明一个wire型变量时对齐进行包含一定时延的连续赋值
wire A,B;
wire #10 Z = A & B;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

功能定义:
(1)用assign声明语句

assign a = b & c;
  • 1

(2)用always

always begin 
	#10;
	if ($time >= 100) $finish;
end
  • 1
  • 2
  • 3
  • 4

注意:Verilog模块中的所有过程块是同时执行,也就是并发的。

3.数据类型

1.常量
数值种类
Verilog有下列四种基本的值来表示硬件电路的电平逻辑

0 逻辑0或“假”
1 逻辑1或“真”
x或X 未知
z或z 高阻
  • 1
  • 2
  • 3
  • 4

x意味着信号数值的不确定,即在实际电路里,信号可能为1,也可能为0
z意味着信号处于高阻状态,常见于信号(input reg)没有驱动时的逻辑结果。例如一个pad的input呈现高阻状态时,其逻辑值和上下拉的状态有关系。上拉则逻辑值为1,下拉则为0。
整数数值的表示方法
整形常量有以下4种进制表示形式

二进制整数(b或B)
十进制整数(d或D)
十六进制整数(h或H)
八进制整数(o或O)
表达方式:
<位宽><进制><数字>
<进制><数字>
<数字>
4'b1011 //4bit数值
32'h3022_c0de //32bit数值,下划线_为了增强代码可读性
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Verilog中用parameter来定义常量

parameter msb=7 //定义参数msb为常量7
  • 1

2.变量
wire

wire [n-1:0] 数据名1,..,数据名i;//共有i条总线,每条总线内有n条线路
  • 1

reg

reg [n-1:0] 数据名1,..,数据名i;//共有i条总线,每条总线内有n条线路
  • 1

4.运算符及表达式

1.基本运算符

+ 
-
*
/
  • 1
  • 2
  • 3
  • 4

2.位运算

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

三、运算符与赋值语句

1.逻辑运算符

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

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

2.关系运算符

关系运算符共有以下四种

a < b
a > b
a <= b
a >= b
  • 1
  • 2
  • 3
  • 4

3.等式运算符

在Verilog中存在4种等式运算符

== 等于
!= 不等于
=== 等于
!== 不等于
  • 1
  • 2
  • 3
  • 4

“=== ” 和 “!==”在对操作数进行比较时对某些位的不定值x和高阻值z也进行比较,两个操作数必须完全一致,其结果才是1,否则为0。

4.移位运算符

a >> n 右移运算符
a << n 左移运算符
  • 1
  • 2

5.赋值语句

非阻塞赋值方式,属于并行执行语句
b <= a;
1.在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用;
2.块结束后才能完成这次赋值操作,而所赋的变量值是上次赋值得到的;
3.在编写可综合的时序逻辑块时,这是最常用的赋值方法
  • 1
  • 2
  • 3
  • 4
  • 5
阻塞赋值,属于顺序执行
b = a;
1.赋值语句执行完,块才结束;
2.b的值在赋值语句执行完后立刻就改变;
  • 1
  • 2
  • 3
  • 4

在实际Verilog代码设计时,切记不要在一个过程结构中混合使用阻塞赋值与非阻塞赋值。两种赋值方式的混用时,时序不容易控制,很容易得到意外的结果。
在设计电路时,always时序逻辑块中多用非阻塞赋值,always组合逻辑块中多用阻塞赋值;initial块中一般多用阻塞赋值。

always @(posedge clk) begin
	a <= b;
end

always @(posedge clk) begin
	b <= a;
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6.块语句

begin
	语句1;
	语句2;
	.
	.
	语句n;
end
1.块语句是按顺序执行的
2.每条语句的延时,是相对于前一条语句的仿真时间而言
3.最后一条语句执行完,程序流程控制才跳出语句块	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、条件语句、循环语句、块语句与生成语句

1.条件语句

//第一类,没有else语句
if (condition) true_statement;

//第二类,只有一条else语句
if (conditon)
	true_statement;
else
	false_statement;
	
//第三类,嵌套的if_else_if语句
if (condition) 
	true_statement;
else if (condition)
	true_statement;
else if (condition)
	true_statement;
else
	default_statement;
//允许一定形式的表达式简写方式
if (expression) 等同于 if(expression == 1)
if (!expression) 等同于 if(expression != 1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

为避免歧义,在条件语句中加入begin与end关键字是一个很好的习惯

if begin
	if(sel == 2'b1) begin
		sout = p1s;
	end
	else begin
		sout = p0;
	end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.case 语句

reg[3:0] condition
case(condition)
	2'b00: statement1;
	2'b01: statement2;
	2'b10: statement3;
	2'b11: statement4;
	default: default_statement;
endcase
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.循环语句

1.forever语句:连续的执行语句
forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever

forever 语句;
forever 
	begin
		多条语句;
	end
  • 1
  • 2
  • 3
  • 4
  • 5

2.repeat语句
repeat 的功能是执行固定次数的循环,它不能像 while 循环那样用一个逻辑表达式来确定循环是否继续执行。repeat 循环的次数必须是一个常量、变量或信号。

repeat(表达式) 语句
repeat(表达式)
	begin
		多条语句;
	end
repeat (11) begin //重复11次
	#10;
	counter3 = counter3 + 1'b1;
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.while语句

while(表达式)
	begin
		多条语句;
	end
  • 1
  • 2
  • 3
  • 4

4.for语句

for(表达式1;表达式2;表达式3) begin
...
end

执行过程:
1)先求解表达式1
2)求解表达式2,若为真,执行for语句中指定的内嵌语句。然后执行下面的第(3)步。若为假,则结束循环,转第(5)步。
3)若表达式为真,在执行指定的语句后,求解表达式3
4)转回上面的第(2)步骤继续执行
5)执行for语句下面的语句
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.顺序块和并行块

1.顺序块(也称过程块)

begin
	多条语句;
end
具有以下特点:
顺序块中的语句是一条接一条按顺序执行的
  • 1
  • 2
  • 3
  • 4
  • 5

2.并行块

fork
	多条语句;
join
具有以下特点:
并行块内的语句并发执行
  • 1
  • 2
  • 3
  • 4
  • 5

五、结构说明语句

1.initial和always说明语句

一个程序模块可以有多个initialalways过程块。
每个initialalways语句在仿真的一开始便同时立即开始运行。
一个模块可以包含多个initialalways语句,但两种语句不能嵌套使用。
每个initial语句或always语句都会产生一个独立的控制流,执行时间都是从0时刻开始。
initial语句从0时刻开始,只执行一次,多个initial块之间是相互独立的。
如果initial块内包含多个语句,需要使用beginend组成一个块语句。
如果initial块内只要一条语句,关键字beginend可使用也可不使用。

initial
	begin
	多条语句;
	end
注意:
用initial语句来生成激励波形作为电路的测试仿真信号
initial语句在模块中只执行一次
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

always后跟着的过程块是否运行,则要看它的触发条件是否满足,如满足则运行过程块一次,再次满足则再运行一次,循环往复直至仿真过程结束。

always <时序控制> <语句>
注意:
always语句则是不断地活动着,直到仿真过程结束
always的控制可以是边沿触发也可以是电平触发,多个信号中间用**or**连接
always里面赋值左边必须申明成reg
  • 1
  • 2
  • 3
  • 4
  • 5

2.task和function说明语句

task和function说明语句的不同点:
1.函数只能与主模块共用一个仿真时间单位,而任务可以定义自己的仿真时间单位。
2.函数不能启动任务,而任务能启动其他任务和函数。
3.函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量。
4.函数返回一个值,而任务则不返回值。
1.task说明语句

task <任务名>
	<端口及数据类型声明语句>
	<语句1>
endtask
//任务调用
my_task(v,w,x,y,z);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

任务调用变量(v,w,x,y,z)和任务定义的I/O变量(a,b,c,d,)之间是一一对应的。
2.fuction说明语句
函数的目的是返回一个用于表达式的值

function <返回值的类型或范围>
	<端口说明语句>
	<变量类型说明语句>
	begin
		<语句>
		......
	end
endfunction
//函数的调用是通过将函数作为表达式中的操作数来实现
<函数名> (<表达式>, ... ,<表达式>)
word = control?{getbyte(msbyte),getbyte(lsbyte)} : 0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

函数的使用规则:
1.函数的定义不能包含有任何的时间控制语句,即任何用#、@或wait来标识的语句
2.函数不能启动任务
3.定义函数时至少要有一个输入参量
4.在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数名形同的名字。

3.常用的系统任务

  1. $ display 和 $ write任务

这两个函数和系统任务是用来输出信息。这两个任务的作用基本相同。$ display 自动地在输出后进行换行,$ write可以在一行中输出多个信息。

$display (p1,p2,p3,...,pn);
$write (p1,p2,...,pn);
  • 1
  • 2

总结

参考文献:Verilog数字系统设计教程——夏宇闻

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/784440
推荐阅读
相关标签
  

闽ICP备14008679号