Verilog学习笔记(上)

简介: Verilog学习笔记

一、绪论


1.1举个例子对verilog语言进行总体性概括


例1:描述一个adder的三位加法器

1670678874945.jpg

看该简单的代码编写,咱们可以得到如下结论:


verilog HDL 程序是由模块构成的。每个模块的内容都是嵌套于module和endmodule两个语句之间。每个模块实现特定的功能。模块之间可以进行像C语言一样的嵌套方式。这样整合成模块就有一个好处:大型数字电路可以分割成很多小的模型来实现特定的功能,最后通过顶层的模块调用小模块来实现整体的功能。

每个模块都要进行端口定义,并且输入输出口,然后对模块的功能进行行为的逻辑描述。

Verilog HDL程序的书写自由,一行可以书写几个语句,一个语句也可以分写很多行,除了endmodule语句以外,每一个语句以及数据的定义都是要最后写上分号的。

关于注释:两种方法咯,和C相同。/……/or//……


1.2 解释一下模块的结构是什么?

1670678958586.jpg

看上面这个图示,左边为程序模块,右边为电路图。左边的代码部分是对右边电路图的描述。观察左边其可以概括为四部分:端口定义、I/O说明、内部信号说明、功能定义。这部分全部夹在module和endmodule之间,也就是说以后的所有verilog代码都是如此结构构成的。

对上述代码简单做一个分析:block就是端口定义名字了。input与output就是I/O说明,后面两个语句就是逻辑功能的定义,非常简单。

模块的端口如何定义呢,如下图。

1670678968844.jpg

I/O说明的格式如何定定义呢,两种方式。其一,直接定义法:

1670678982091.jpg

其二,也可以定义在模块端口中:

1670678993242.jpg

内部信号说明怎么定义呢,我们常用的往往是wire与reg两种变量。其定义的规则一般如下,对这方面具体的阐述放在后面介绍。

1670679001901.jpg

介绍完以上这些,最难的还是功能如何定义的问题。有三种方法,

其一,用”assign”语句,常用于组合逻辑电路。

其二,用实例元件,类似于C语言的调用库函数,这些元件都是标准的电路。

其三,用”always”语句,常用于组合逻辑与时序电路。

我这里只是做一个简单的阐述,具体怎么用,后面再说。


注意的一个点就是功能部分执行的先后顺序。上面讲的三个语句从宏观来看都是一起执行的。对,就是类似于并发。但是呢,always语句不一样,微观来看,他的内部是顺序执行的,比如它内部可能你会写if…else语句,这明显只能顺序执行。


Verilog 设计方法


Verilog 的设计多采用自上而下的设计方法(top-down)。即先定义顶层模块功能,进而分析要构成顶层模块的必要子模块;然后进一步对各个模块进行分解、设计,直到到达无法进一步分解的底层功能块。这样,可以把一个较大的系统,细化成多个小系统,从时间、工作量上分配给更多的人员去设计,从而提高了设计速度,缩短了开发周期。

1670679032046.jpg

1670679066432.jpg

Verilog 的设计流程,一般包括以下几个步骤:


需求分析


工作人员需要对用户提出的功能要求进行分析理解,做出电路系统的整体规划,形成详细的技术指标,确定初步方案。例如,要设计一个电子屏,需要考虑供电方式、工作频率、产品体积、成本、功耗等,电路实现采用 ASIC 还是选用 FPGA/CPLD 器件等。


功能划分


正确地分析了用户的电路需求后,就可以进行逻辑功能的总体设计,设计整个电路的功能、接口和总体结构,考虑功能模块的划分和设计思路,各子模块的接口和时序(包括接口时序和内部信号的时序)等,向项目组成员合理分配子模块设计任务。


文本描述(verilog代码编写)


可以用任意的文本编辑器,也可以用专用的 HDL 编辑环境,对所需求的数字电路进行设计建模,保存为 .v 文件。


功能仿真(前仿真)


对建模文件进行编译,对模型电路进行功能上的仿真验证,查找设计的错误并修正。


此时的仿真验证并没有考虑到信号的延迟等一些 timing 因素,只是验证逻辑上的正确性。


逻辑综合


综合(synthesize),就是在标准单元库和特定的设计约束的基础上,将设计的高层次描述(Verilog 建模)转换为门级网表的过程。逻辑综合的目的是产生物理电路门级结构,并在逻辑、时序上进行一定程度的优化,寻求逻辑、面积、功耗的平衡,增强电路的可测试性。


但不是所有的 Verilog 语句都是可以综合成逻辑单元的,例如时延语句。


布局布线


根据逻辑综合出的网表与约束文件,利用厂家提供的各种基本标准单元库,对门级电路进行布局布线。至此,已经将 Verilog 设计的数字电路,设计成由标准单元库组成的数字电路。


时序仿真(后仿真)


布局布线后,电路模型中已经包含了时延信息。利用在布局布线中获得的精确参数,用仿真软件验证电路的时序。单元器件的不同、布局布线方案都会给电路的时序造成影响,严重时会出现错误。出错后可能就需要重新修改 RTL(寄存器传输级描述,即 Verilog 初版描述),重复后面的步骤。这样的过程可能反复多次,直至错误完全排除。


FPGA/CPLD 下载或 ASIC 制造工艺生产


完成上面所有步骤后,就可以通过开发工具将设计的数字电路目标文件下载到 FPGA/CPLD 芯片中,然后在电路板上进行调试、验证。


如果要在 ASIC 上实现,则需要制造芯片。一般芯片制造时,也需要先在 FPGA 板卡上进行逻辑功能的验证。


二、 基本语法框架


基本参考夏宇闻的《verilog VHDL》。现在列出具体框架如下:


1670679125758.jpg


2.1 编译预处理


在Verilog HDL语言中,为了和一般的语句相区别,这些预处理命令以符号“ `”开头(注意这个符号是不同于单引号“ '”的)。这些预处理命令的有效作用范围为定义命令之后到本文件结束或到其它命令定义替代该命令之处。

Verilog HDL提供了以下预编译命令:

`accelerate,`autoexpand_vectornets,`celldefine,`default_nettype,`define,`else,
`endcelldefine,`endif,`endprotect,`endprotected,`expand_vectornets,`ifdef,`include,
`noaccelerate,`noexpand_vectornets , `noremove_gatenames , `noremove_netnames ,
`nounconnected_drive , `protect , `protecte , `remove_gatenames , `remove_netnames ,
`reset,`timescale,`unconnected_drive


在这一小节里只对常用的define、include、`timescale进行介绍:


宏定义 `define:用一个指定的标识符(即名字)来代表一个字符串

`define 标识符(宏名) 字符串(宏内容)
如:`define signal string 
它的作用是指定用标识符signal来代替string这个字符串,在编译预处理时,把程序中在该命令以后
所有的signal都替换成string。这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用
一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”,在编译预
处理时将宏名替换成字符串的过程称为“宏展开”。`define是宏定义命令。 
其他细节看书本57页。


“文件包含”处理`include:一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。

1670679161874.jpg


[例1]: 
(1)文件aaa.v 
module aaa(a,b,out); 
  input a, b; 
  output out; 
  wire out; 
  assign out = a^b; 
endmodule 
(2)文件 bbb.v 
`include "aaa.v" 
module bbb(c,d,e,out); 
  input c,d,e; 
  output out; 
  wire out_a; 
  wire out; 
  aaa aaa(.a(c),.b(d),.out(out_a)); 
  assign out=e&out_a; 
endmodule 
//相当于如下代码
module aaa(a,b,out); 
input a, b; 
output out; 
wire out; 
assign out = a ^ b; 
endmodule 
module bbb( c, d, e, out); 
input c, d, e; 
output out; 
wire out_a; 
wire out; 
 aaa aaa(.a(c),.b(d),.out(out_a)); 
assign out= e & out_a; 
endmodule
//更多关于include的细节关注课本,这里提一下include的功能


时间尺度 `timescale:跟在该命令后的模块的时间单位和时间精度。

`timescale 命令的格式如下: 
`timescale<时间单位>/<时间精度> 
在这条命令中,时间单位参量是用来定义模块中仿真时间和延迟时间的基准单位的。时间精度参量是
用来声明该模块的仿真时间的精确程度的,该参量被用来对延迟时间值进行取整操作(仿真前),因此
该参量又可以被称为取整精度。如果在同一个程序设计里,存在多个`timescale命令,则用最小的时
间精度值来决定仿真的时间单位。另外时间精度至少要和时间单位一样精确,时间精度值不能大于时
间单位值。
举例:`timescale 1ns/1ps
在这个命令之后,模块中所有的时间值都表示是1ns的整数倍。这是因为在`timescale命令中,定义
了时间单位是1ns。模块中的延迟时间可表达为带三位小数的实型数,因为 `timescale命令定义时间
精度为1ps. `timescale 10us/100ns
在这个例子中,`timescale命令定义后,模块中时间值均为10us的整数倍。因为`timesacle 命令定
义的时间单位是10us。延迟时间的最小分辨度为十分之一微秒(100ns),即延迟时间可表达为带一位
小数的实型数。 
//更多关注书本

条件编译命令ifdef、else、endif :时希望对其中的一部分内容只有在满足条件才进行编译,也就是对一部分内容指定编译的条件。

1) `ifdef 宏名 (标识符) 
  程序段1 
  `else 
  程序段2 
  `endif 
它的作用是当宏名已经被定义过(用`define命令定义),则对程序段1进行编译,程序段2将被忽略;
否则编译程序段2,程序段1被忽略。其中`else部分可以没有,
2) `ifdef 宏名 (标识符)
  程序段1 
  `endif 
//更多关注书本


相关文章