记录Verilog的一些关键点

Verilog HDL模块结构

每个Verilog HDL模块都包括4个主要部分:

  1. 模块声明
  2. 端口定义
  3. 数据类型声明
  4. 逻辑功能描述

如图:
在这里插入图片描述
基本的代码结构:

//模块声明//端口声明
module模块名(输入/输出端口列表);
input输入端口列表;
output输出端口列表;
inout双向端口列表;

//数据类型声明,任务或函数声明
wire [n-1:0]数据名;
reg [n-1:0]数据名;

task任务名;
端口及数据类型声明;
其他语句;
endtask

function函数名;
端口声明;
局部变量定义;
其他语句;
endfunction

//逻辑功能描述
assign结果-表达式;
//数据流描述方式
always@(敏感信号列表)
//行为描述方式
begin
//过程赋值语句
/ /if-else语句、case语句//for循环语句
//调用任务、函数
end

//元件例化结构描述方式
门元件关键字例化门元件名(端口列表);
调用模块名例化模块名(端口列表);
endmodule

Verilog HDL基本语法

语言要素

  1. 注释
//  单行注释
/*多行
注释*/  
  1. 关键字,所有关键字都是小写的
  2. 标识符,任意一组字母、数字、“ ”(下画线)和“$”(美元符号)的组合,但标识符的第一个字符必须是字母(A ~ Z,a~ z)或是下画线“ ”,不能以数字或美元符号“$”开始。

常量

Verilog HDL中的常量主要有3种类型:

  1. 整数
  2. 实数
  3. 字符串

其中,整数型常量是可以综合的,而实数型和字符串型常量是不可综合的。

Verilog中四种逻辑状态:

逻辑状态 含义
0 低电平、逻辑0、“非”
1 高电平、逻辑1、“真”
z 高阻态
x 不确定或未知的逻辑状态

Verilog HDL中的数据都是在上述4类逻辑状态中取值,其中z和x都不区分大小写,也就是说,值10xz与值10XZ是等同的,表示同一个数据。

  • 整数
    符 号 ( + / − ) + 位 宽 + ′ + 进 制 ( b 、 o 、 d 、 h ) + 数 字 符号(+/-)+位宽+'+进制(b、o、d、h)+数字 +/+++bodh+
    例如:位宽为8位的十六进制数34: 8 ′ h 34 8'h34 8h34
    1. 在较长的数字之间可以用下画线分开
    2. 当数字不说明位宽和进制时,默认值为32位的十进制数
    3. 如果没有定义一个整数的位宽,其宽度为相应值中定义的位数
    4. x或z在二进制中代表1位x或z,在八进制中代表3位x或z,在十六进制中代表4位x或z,其代表的宽度取决于所用的进制
    5. 如果定义的位宽比实际的位数大,通常在左边填0补位。但如果数字最左边一位为x或z,就相应地用x或z在左边补位;如果定义的位宽比实际的位数小,则左边的位被截掉。
    6. “?”是高阻态z的另一种表示符号。在数字的表示中,字符“?”和z(或Z)是完全等价的,可互相替代。
    7. 整数可以带符号(正、负号),并且正、负号应写在最左边。负数通常表示为二进制补码的形式。
    8. 在位宽和′之间以及进制和数字之间允许出现空格,但在′和进制之间以及数字之间不允许出现空格。
  • 实数,在Verilog HDL中,实数就是浮点数,实数的定义方式有两种
    1. 十进制格式。例如:1.0,必须有小数点和后面的数字
    2. 科学计数法,由数字和字符e(E)组成,e(E)的前面必须有数字而后面必须为整数。例如:235.1e4
  • 字符串,符串是由一对双引号括起来的字符序列,出现在双引号内的任何字符(包括空格和下画线)都将被作为字符串的一部分。例如:“Simulation”。
    字符串的作用主要是用于仿真时显示一些相关的信息或指定显示的格式。

变量和数据类型

在Verilog HDL中,根据赋值和对值的保持方式的不同,可将数据类型分为两大类:

  1. 线网(net),相当于硬件按电路中的各种物理连接(导线和节点)来连接各个模块及输入/输出。其特点是输出的值紧跟输入值的变化而变化,没有电荷保持作用(trireg除外)
  2. 变量(variable),variable型变量必须放在过程语句(always、initial)中,通过过程赋值语句赋值;
    • reg型,定义:reg[n-1:0] 数据名;默认初始值为x,reg型变量并不意味着一定对应着硬件上的触发器或寄存器,在综合时,综合器会根据具体情况来确定将其映射成寄存器还是映射为连线。
    • integer型,是整数寄存器,这种寄存器中存储整数值,常用于对循环控制变量的说明,如用来表示循环次数等。integer型变量的初始值为x。整数寄存器中最少可以容纳一个32位的数,但是不能做位向量访问。
    • real:real是实数型寄存器,一般用于测试模板中存储仿真时间。real型变量的默认值为0,当将值z和x赋予real类型寄存器时,这些值被当做0
    • time:time是时间寄存器,用于存储和处理时间,通常用在系统函数$time中。

参数

在Verilog HDL中,参数型数据是被命名的常量,在仿真开始前对其赋值,在整个仿真过程中其值保持不变。

参数通常出现在模块内部,用来定义状态机的状态、数据位宽及延时大小等。

定义:
parameter 参数名 = 表达式
例如:
parameter msb = 15

PS:在Verilog HDL中还提供了另一种定义常量的方法,就是编译向导语句宏替换′define。′define是一种全局性的定义,在遇到′undef之前定义的内容始终有效;而parameter是一种局部定义,在模块内部使用并且可以被灵活改动,这是parameter的一个重要特征。

向量

  1. 标量与向量
    • 位宽为1位的变量称为标量,如果在变量声明中没有指定位宽,则默认为标量(1位)。
    • 位宽大于1位的变量(包括net型和variable型)称为向量(vector)。向量通过位宽定义语法 [msb:lsb] 指定地址范围。
    • MSB和LSB必须是常数值或parameter,或者是可以在编译时计算为常数的表达式,且可以为任意符号的整数值,即整数、负数或零均可。
  2. 位选择和域选择
    在向量中,可以指定其中的某一位或若干相邻位进行操作,这些指定的一位或相邻位分别称为位选择或域选择(部分选择)

存储器

系统设计中,经常需要用到(memory)。Verilog HDL通过对reg型变量建立数组来对存储器建模,数组中的每个单元通过一个数组索引进行寻址。memory型数据是通过扩展reg型数据的地址范围来生成的。————类似于二维数组

定义格式:
reg [n-1 : 0] 存储器名 [m-1 : 0];

其中,reg [n-1:0] 为存储器的字长,定义了存储器中每个存储单元的大小,即该存储单元是一个n位的寄存器;存储器名后的 [m-1:0] 或 [m:1] 为存储器的容量,定义了该存储器中有多少个这样的寄存器

不允许对存储器进行位选择和域选择。不过,可以首先将存储器的值赋给寄存器,然后对寄存器进行位选择和域选择。

运算符

位拼接运算符

位拼接运算符({})是将两个或两个以上操作数或操作数的某几位拼接在一起,形成一个新的表达式。

定义格式:
{op1, op2, op3, … opn}
例如:
{a, c[2 : 1]}

位拼接运算符还可以嵌套使用,如果多次拼接同一个操作数,重复的次数可以用常数指定,这时位拼接运算符又称为复制运算符。其使用格式如下:

{重复次数{op}}
例如:
{2{a}}等同于{a, a}

位拼接运算符中不允许拼接位宽不确定的常数,例如:
{a, 2}

缩位运算符

缩位运算符是单目运算符,其运算规则类似于位运算符,但运算过程不同。首先将操作数的第一位与第二位进行运算,其次将运算结果与第三位进行运算,依次类推,直至最后一位例如:

reg [3:0] a;
y = &a;// 此时的y=a[0]&a[1]&a[2]&a[3]

等式运算符

符号 含义
== 等于
!= 不等于
=== 全等
!== 不全等

“==”和“!=”又称为逻辑等式运算符,其结果由两个操作数的值决定。由于操作数中某些位可能是x或z,结果可能是不确定值x。而“===”和“!==”运算符则不同,它在操作数进行比较时对某些不确定值x和z也进行比较,两个操作数必须完全一致,其结果才是1,否则为0。

Verilog HDL的基本语句

可综合性的设计语句

可综合是指所设计的代码和指令能转化为具体的电路网表结构,在基于FPGA/CPLD的设计中,综合就是将Verilog HDL描述的行为级或功能级电路模型转化为RTL级功能块或门级电路网表的过程。

时间控制语句

  1. 延时控制,为行为语句的执行指定一个延时时间的时间控制方式。程序执行到该语句就会暂停下来,等待这个值规定的若干个时间单位,然后再继续执行后面的语句。
    • 语句前延时,格式: #10 b = a;当仿真进行到这条语句时,将等待10个时间单位,然后才执行后面的语句,将a的值赋给b。
    • 单独延时,格式: #延时时间;在这种延时控制情况下,仿真进程进行到该语句时,不进行任何操作,只是处于一个等待状态,等到延时时间量过去后,结束该条语句。
    • 语句内延时,格式: 结果 = # 延时时间 表达式;延时定义的位置处于赋值语句中间,作用是把赋值过程分隔成两步。
  2. 事件控制,事件控制就是把某个事件作为执行某个操作的条件。在Verilog HDL中,一个事件通常是指一个变量、线网信号或表达式的值发生变化。
    • 边沿敏感事件:边沿敏感事件使用符号“@”定义。例如:
      @(posedge clk) dout = din; // 在时钟clk上升沿跳变时,将din的值赋给dout
      
    • 电平敏感事件:电平敏感事件使用关键字“wait”
      wait (en) dout = din; // 当括号的条件满足时,就会执行后面的语句
      

过程语句

Verilog HDL中的过程语句有两种:initial过程语句和always过程语句。一个模块中可以包含多个initial和always语句,每一个initial或always语句都是一个独立的执行过程,并且这些执行过程彼此之间都是并行执行,即这些语句的执行顺序与其在模块内的顺序无关。每个执行过程都是在仿真时间0时刻同时开始的。

  1. initial过程语句, 仅执行一次,常用于仿真中的初始化,initial语句没有触发条件,如果initial过程语句中包含多条语句,必须用begin-end顺序块语句包含起来;如果initial语句中只有一条语句,则begin-end块语句可缺省。格式:
    initial
    	begin
    		语句1;
    		语句2...
    		语句n;
    	end
    
  2. always过程语句 ,不断重复执行的,只要满足其规定的条件,always语句就执行,如果在整个仿真过程中多次满足这个条件,always就会被多次执行。格式:
    always @(敏感信号列表)
    	begin
    		// 过程复制
    		// if-else, case等条件语句
    		// for, while, repeat等循环语句
    		// task, function调用
    	end
    

块语句

  1. 顺序块,begin-end,顺序块中的语句是按顺序执行的
  2. 并行块,fork-join,并行块fork-join中的所有语句都是并发执行的,例如:
    fork
    	b = a;
    	c =b;
    join
    // 由于fork-join并行块内的语句是并发执行的
    //最终b和c的值是不同的,b的值等于a的值,而c的值等于改变之前b的值。
    

赋值语句

  1. 持续赋值语句, 持续赋值语句使用关键字“assign”,主要用于对组合逻辑电路的行为进行描述。持续赋值语句只能用来对wire型变量进行赋值,而不能对寄存器型变量进行赋值。例如:assign f = a ^ b;
  2. 过程赋值语句,过程赋值语句是在initial语句或always语句内对reg型变量进行赋值的赋值语句,在经过过程赋值后,这些变量的取值将保持不变,直到另一条过程赋值语句对变量重新赋值为止。
    1. 阻塞赋值,“=”,阻塞赋值语句先计算右侧表达式的值,然后赋值给等号左端目标,而且在完成整个赋值之前不能被其他语句打断,也就是说,阻塞赋值在该语句结束时就立即完成赋值操作,即b的值在该条语句结束后立刻改变。如果在一个块语句中有多条阻塞赋值语句,则在前面的赋值语句完成之前,后面的语句不能被执行,仿佛被阻塞了一样,因此称为阻塞赋值方式。
    2. 非阻塞赋值,“<=”,非阻塞赋值在整个过程块结束时才完成赋值操作,即b的值并不是立刻就改变的。

猜你喜欢

转载自blog.csdn.net/qq_39021670/article/details/109551656