Verilog HDL笔记

《设计与验证 Verilog HDL》

设计与验证的发展历程

早期:卡诺图设计,面包板验证

中期:原理图设计,EDA工具仿真验证

后期:硬件描述语言HDL设计,EDA工具仿真验证

抽象层次不断提高

HDL可以从算法/系统级>功能级>行为级>寄存器传输级(RTL)>门级和开关级不同的层次描述数字电路系统。

通过EDA工具将高层次的电路描述解析到门级等低层次的电路描述(网表)的过程就叫做"综合"(Synthesize),或者称逻辑综合(综合时会根据"约束条件"优化)

最成熟的综合是RTL级到门级的综合

 

Verilog不仅定义了语法,还对每个语法结构都清晰定义了仿真语义,从而便于仿真调试

Verilog集成了C语言的语法结构和操作符,易学易用,具有很强的扩展性

VHDL(Very High Speed Integrated Circuit HDL,超高速集成电路描述语言)的特点是描述严谨

 

几种设计方法:

原理图直观,便于理解,但在大型设计中可维护性差,不利于提高模块重用性

HDL输入:利于自顶向下设计,利于模块划分和重用,可移植性好,通用性好,设计不因芯片工艺和结构变化而变化,利于向ASIC移植

波形输入和状态机输入:是最常用的辅助设计方法,EDA工具可自动根据两种输入生成HDL代码,应用受局限,维护性不高

推荐初学者:首选HDL方式,在某些要求使用图形描述设计顶层的情况下才使用原理图,不要在设计顶层以外的其他层次使用原理图,不要依赖波形设计工具(因为复杂的测试激励无法用波形工具描述)

 

Verilog和VHDL:

两者都能胜任数字电路系统设计任务

VHDL最初用作文档来描述数字硬件的行为,描述性和抽象性更强,更适合描述更高层次(行为级,系统级)

Verilog最初为更简捷、有效的描述数字电路和仿真而设计,易学易懂

在这两者基础上又发展处很多更抽象的硬件描述语言:SystemVerilog、Superlog、SystemC、CoWare C等

Verilog寄存器和线网两种数据类型定义清楚,时序和组合电路描述简洁,能帮助快速了解硬件设计的基本概念。

但VHDL和Verilog各有所长,并无优劣之分,最重要的是建模方法与思想

推荐初学者:从Verilog学起

 

Verilog和C语言:

区别:

互连(connectivity):wire型变量配合驱动结构可有效表示网线互连

并发(concurrency):并行执行

时间(time):Verilog定义了绝对和相对的时间度量,仿真时可描述信号之间的时间关系

HDL语言与软件语言(C,C++等)有本质区别,评判HDL代码的最终标准是实现的硬件电路的性能(面积和速度)

一个硬件设计的最终性能,很大程度上取决于设计工程师所构想的硬件实现方案的合理性

从软件设计转行的初学者,片面追求代码的整洁、简短是错误的,是与评价HDL的标准背道而驰的

正确的方法是,首先对所要实现的硬件电路有一个清楚的认识,对硬件结构与连接了解十分清楚,再用HDL语句描述出来

验证时,常用C语言编写测试向量,与Verilog在仿真器中通信,用于验证

 

描述分级

系统级:对系统整体功能和性能指标进行衡量

功能级:将系统功能划分为可实现的具体功能模块,大致确定模块间的接口,描述每个模块的时序约束

行为级:明确每个模块所有的接口和边界,模块内部功能,外部接口和行为都已经清晰。常用于编写仿真测试激励(延时描述、监视描述)

寄存器传输级:不关注寄存器和组合逻辑的细节,使用HDL语言描述寄存器到寄存器间的逻辑功能描述电路——一般对此设计仿真

门级:目前要直接使用门级描述的情况一般是ASIC和FPGA设计中有面积或时序要求较高的模块

布局规划与布局布线:门级描述映射到目标器件中

时序仿真:将布局布线的延时信息反标注到设计网表中进行仿真,简称后仿真。包含门延时和线延时,能较好反映芯片实际工作情况。主要目的是发现时序违规的情况

 

所有的电路单元是并行工作的,相互之间没有顺序关系,即使是最小的单元也是如此

模块中只有定义了时钟边沿的行为是与跳变沿有关的,其余(例如+,-,×,÷,多路选择器,译码器等)如果没有定义边沿触发,就与边沿无关,其输出与输入之间的延时只有门延时和线延时,线路越长,此延时越大

 

assign:连续赋值语句

#3:模拟组合逻辑的延时,表示经过3个延时单位,再进行赋值

timescale 1ns/100ps:定义时间单位/仿真时间精度

{}:是Verilog的合并符号,将多个变量合并成一个组合变量,可用于批量赋值

xor:是Verilog自带的逻辑门原语

实例化:调用功能模块

在模块中实例化其他模块的描述方式称为结构化描述

 

Verilog的3种描述方法:

数据流描述:assign语句——连续赋值语句

行为描述:always或initial语句——其中包含的语句称为过程赋值语句

结构化描述:实例化已有的模块(包括Module实例化、门实例化、用户定义原语UDP实例化)

 

基本词法:

Verilog对大小写敏感,书写时要格外注意

Verilog中所有关键字都是小写

Verilog中标识符(内部信号名,变量名)由字母、数字、$、和_组成,第一个字符必须是字母或_

//和/* */表示注释,某些控制编译过程的指令也是以注释的形式出现,例如/* synthesis syn_black_box */

间隔:空格、制表符、换行符

转义字符:\n换行符;\t制表符;\\表示\本身

 

模块和端口:

Verilog中,module是基本的组成单元

建议在一个Verilog文件中只放一个module定义,且使文件名与module名称一致

module 模块名称 (端口列表)

//变量声明

input [1:0], output, inout,

reg, wire, parameter,

function, task, …

//语句,以下语句在module中是并行的关系,无任何顺序关系,其文本上的顺序不改变module的功能

initial

always

module实例化

门实例化

UDP实例化

assign

endmodule

有些module不包含输入输出端口,一般用于内部已经实例化了激励的封闭系统,只用于仿真,不用于实际系统

input默认为wire类型(貌似不可以声明为reg类型);output在always或initial中赋值时默认是reg,否则是wire;inout一般设为tri类型(表示有多个驱动源,如无驱动则为三态)

建议将所有的声明放到所有语句之前,增加可读性

 

always的用法

1.always@后面内容是敏感变量,always@(*)里面的敏感变量为*,意思是说敏感变量由综合器根据always里面的输入变量自动添加,不用自己考虑。

2.如果没有@,那就是不会满足特定条件才执行,而是执行完一次后立马执行下一次,一直重复执行

3.通常情况下,使用方法是:always@(posedge clk_out_0, negedge reset_n)

 

Error (10028): Can't resolve multiple constant drivers for net……

上面的代码在quartusII里面就会出现题目的错误提示,其原因就是在两个always语句里面都对out1,out2信号赋值了,而两个always是并行快,所以提示出现多重驱动的情况

解决办法:将两个always合并成一个

 

结构化描述

结构化描述就是在设计中实例化已有的功能模块,包括门原语、用户自定义原语UDP,和其他模块module

需要将模块实例与外部信号相连接,模块实例的端口连接规则:

Input:缺省为线网wire类型

Output:寄存器(在过程赋值语句中被赋值),或者是线网类型

Inout:缺省为线网类型,定义为tri双向

与之相连的信号类型为:

与input相连的,可以使一个线网或寄存器

与output,相连的一定是驱动一个线网

与inout先练,输入时从一个线网驱动而来,输出时驱动到一个线网(切记,只有线网类型可以驱动inout端口,否则编译出错)

 

实例的端口对应方式有两种:

(1)名称对应:外部信号与模块端口名称相对应,顺序可随意

模块名 实例名称(

    .X(E_X),

    .Y(E_Y),    //没有可留空

    ……

    );

(2)位置对应:按顺序对应(与函数传递参数类似),没有则留空

模块名 实例名称(E_X, E_Y, E_SUM, E_C_out);

 

参数化

上面讲了实例化,这里讲参数化

module中的参数一般用作定义常量

当实例化某个模块时,可以修改参数的值,实现不同的特性,是通过"新参数直接代入""参数重定义"来完成的。

方法:

1、defparam关键字重新定义模块参数——Altera自动生成的通用模块定制采用

此方法在某些综合器中失效(应采用第2种)

defparam

    module.parameter = ,

    ……

2、直接在实例化时代入参数——Xilinx自动生成的通用模块定制采用

#(……,……,……)参数要按顺序列出,不能遗漏和颠倒

你可能感兴趣的:(Verilog)