一、Verilog HDL简介 HDL :Hardware Description Language 硬件描述语言。 VHDL or Verilog ? 毫无疑问,新手选Verilog就对了,原因一是对新手友好,有过C语言底子的很快就能上手;原因二是现目前公司基本使用Verilog。 鉴于Verilog 1995标准有些地方比较拉跨,目前基本采用2001标准。 学习Verilog的基本都是FPGA/IC前端预备军,其他就不再赘述了。
二、Verilog模型Verilog模型可以是实际电路不同级别的抽象。这些抽象的级别和它们对应的模型类型共有以下五种: 1) 系统级(system) 2) 算法级(algorithmic) 3) RTL级(RegisterTransferLevel): 4) 门级(gate-level): 5) 开关级(switch-level) 目前,用门级和RTL级抽象描述的Verilog HDL模块可以用综合器转换成标准的逻辑网表;用算法级描述的Verilog HDL模块,只有部分综合器能把它转换成标准的逻辑网表;而用系统级描述的模块,目前尚未有综合器能把它转换成标准的逻辑网表,往往只用于系统仿真。 其实不用纠结这么多,我们设计基本是行为RTL级,初学时也不必纠结什么电路,只要功能运行正常就OK。大佬都说“看到代码背后的电路”,初期真是强人锁男。待到一定程度后,再来研究代码优化,电路优化。 Verilog模块Verilog的基本设计单元是“模块”。一个模块是由两部分组成的,一部分描述接口,另一部分描述逻辑功能,即定义输入是如何影响输出的。 下面举例说明:
基础-1
可以看到模块由关键字module....endmodule 确定。 module 模块名(接口信号); //信号声明 //功能描述 endmodule 要求: 1. 模块名具有意义;2. 一个.v文件只有一个模块。
Verilog数据类型虽然平时我们好像就用到reg/wire ,但其实verilog数据类型有多达19种。 了解常用的4种就好:reg、wire、parameter、integer。 4.1常量- 数字 : <位宽><类型><数字> 如: 8’b1100_0010
- X和Z值 : X:不定值;Z:高阻 (同也可用?表示)
- 负数 : 如:-8’d5 ,减号在最前面。
4.2参数型Verilog模块中可使用parameter来定义一个标识符来代表一个常量。 parameter SIZE = 15; 这里不得不提一下localparam 和 define ,它们都是定义一个标识符来代表一个常量。区别如下: | 作用域 | 常用方式 | 语法 | define宏定义 | 整个工程;可跨文件、跨模块 | 全局定义,宏定义单独写一个文件.v | `include “para.v”`define SIZE 15 | parameter | parameter声明所在的模块内部 | 跨模块传递参数 | parameter SIZE = 15; | localparam | 模块内部 | 内部状态机定义 | localparam SIZE = 15; |
4.3变量4.3.1 wire型①线网型,输入输出信号默认为wire型,同时输入信号只能是wire型。 ②模块间端口连接,信号都定义为wire型,即进行电路连线。 ③wire信号定义: wire [7:0] a; ④wire信号赋值:只能使用assign进行连续赋值(阻塞赋值 “=”): assign a = b & c; 4.3.2 reg型①寄存器是数据储存单元的抽象。寄存器数据类型的关键字是reg。但reg型不一定综合成寄存器,具体还要看设计电路。 ②always块中的变量必须定义为reg型,使用非阻塞赋值“<=”。 ③reg型数据定义: reg [7:0] a; ④reg型数据可以赋正值,也可以赋负值。但当一个reg型数据是一个表达式中的操作数时,它的值被当作是无符号值,即正值。 ⑤reg型数据的缺省值为不定值X。 4.3.3 memory型Verilog HDL通过对reg型变量建立数组来对存储器建模,可以描述RAM型存储器,ROM存储器和reg文件。数组中的每一个单元通过一个数组索引进行寻址。 verilog2001支持多维数组。 memory型数据是通过扩展reg型数据的地址范围来生成的。其格式如下: reg [n-1:0] 存储器名[m-1:0]; 如:reg [7:0] mem_a[255:0]; 这个例子定义了一个名为mema的存储器,该存储器有256个8位的存储器。该存储器的地址范围是0到255。注意:对存储器进行地址索引的表达式必须是常数表达式。 这里不得不提一下下面这两种定义的区别: reg [n-1:0] rega; //一个n位的寄存器 reg mem_a [n-1:0]; //一个由n个1位寄存器构成的存储器组 一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。见下例: rega =0; //合法赋值语句 mem_a =0; //非法赋值语句 运算符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是操作数。
优先级:单独运算符优先级最高;不需要刻意去背,书写时使用()便于阅读。 赋值语句和块语句6.1赋值语句在Verilog HDL语言中,信号有两种赋值方式: (1)非阻塞(Non_Blocking)赋值方式( 如 b <= a; ) 1) 块结束后才完成赋值操作。 2) b的值并不是立刻就改变的。 3) 这是一种比较常用的赋值方法。(特别在编写可综合模块时) (2)阻塞(Blocking)赋值方式( 如 b = a; ) 1) 赋值语句执行完后,块才结束。 2) b的值在赋值语句执行完后立刻就改变的。 3) 可能会产生意想不到的结果。 设计时,遵循以下规则: - always块中使用非阻塞赋值
- assign使用阻塞赋值
6.2块语句顺序块: (顺序执行) begin语句1;语句2;...end
并行块: (同时执行) fork语句1;语句2;...end
注:begin/fork后可以加 “:块名” 条件语句和循环语句基本同C语言,较容易理解,不多介绍 条件语句 if..else (可嵌套) if(条件)语句1;else语句2;
case case(变量)情况1: 语句1;情况2: 语句2;endcase
循环语句 integer i;for(i=0;i<10;i=i+1)a <= i;
八、结构说明语句Verilog语言中的任何过程模块都从属于以下四种结构的说明语句。 1) initial说明语句 2) always说明语句 3) task说明语句 4) function说明语句 这里只介绍always: always语句在仿真过程中是不断重复执行的。
其声明格式如下: always <时序控制> <语句>
always 的时间控制可以是沿触发也可以是电平触发的,可以单个信号也可以多个信号,中间需要用关键字 or 连接。 always @(posedge clock or posedge reset) //由两个沿触发的时序逻辑 begin …… end
//组合逻辑直接使用*代替敏感点平,避免遗漏 always @(*) //由多个电平触发的组合逻辑 begin …… end
|