一、硬件描述语言Verilog
粗略地看Verilog与C语言有许多相似之处。分号用于结束每个语句,注释符也是相同的(/* ... */和// 都是熟悉的),运算符“==”也用来测试相等性。Verilog的if..then..else语法与C语言的也非常相似,只是Verilog用关键字 begin和end代替了C的大括号。事实上,关键字begin和end对于单语句块来说是可有可无的,就与C中的大括号用法一样。Verilog和C都对大小写敏感。

当然,硬件和软件的一个重要区别是它们的“运行”方式。硬件设计中用到的许多单元都是并行工作的。一旦设备电源开启,硬件的每个单元就会一直处于运行状态。虽然根据具体的控制逻辑和数据输入,设备的一些单元可能不会改变它们的输出信号,但它们还是一直在“运行”中。相反,在同一时刻整个软件设计中只有一小部分(即使是多软件任务也只有一个任务)在执行。如果只有一个处理器,同一时间点只能有一条指令在执行。软件的其它部分可以被认为处于休眠状态,这与硬件有很大的不同。变量可能以一个有效值而存在,但大多数时间里它们都不在使用状态。 
软硬件的不同行为会直接导致硬件和软件代码编程方式的不同。软件是串行执行的,每一行代码的执行都要等到前一行代码执行完毕后才能进行(中断的非线性或操作系统的命令除外)。

二、模块(module)
一个Verilog模块的开头是关键字module,紧跟其后的是模块名称和端口列表,端口列表列出了该模块用到的所有输入输出名称。接下来是端口声明部分。注意:所有的输入输出既出现在模块第一行的端口列表中,也会出现在端口声明(declaration)部分中。

以下三个模块分别以∶ 结构式(structural)、数据流式(data-flow)及行为式(behavioral)来描述一个二输入与门。
//structural
module AND2 (in1,in2,out);
input in1;
input in2;
output out;
wire in1,in2,out;
and u1 (out,in1,in2);
endmodule

//data flow
module AND2 (in1,in2,out);
input in1;
input in2;
output out;
wire in1,in2,out;
assign out=in1&in2;
endmodule

//behavioral
module AND2 (in1,in2,out); 
input in1; 
input in2; 
output out; 
wire in1,in2; 
reg out; 
always@(in1 or in2); 
out=in1 & in2;
endmodule

结构式的描述∶在这层次中模块是由逻辑闸(Gate Level)连接而成,在这层次的设计工作就好像以前用描绘逻辑闸来设计线路一样。例1中的AND是Verilog的基本元件 (primitive),是Verilog语言预先定义好的函式。
数据流式的描述∶ 它是一种模拟组合函式的方法。当任何输入有所改变时,输出会被重新计算而跟著改变。数据流式只能用来实践组合函式。在这个层次中,要说明数据如何在暂存器中储存与传送,如何处理数据。例2数据流式使用关键字assign进行描述。
行为式的描述∶它是一种使用高阶语言来描述硬件的方式。因Verilog提供很普遍及功能强大的描述方式。在这个层次的设计工作就好像写C语言一样,使用行为式所描述的模块其描述与真实的电路可能毫无关连。甚至某些行为式模块可能硬件实践。这种特性是Verilog的优点也是缺点。 例3中的行为式描述有一个使用关键字always进行描述。

三、Verilog中端口的描述
1、端口的位宽最好定义在I/O说明中,不要放在数据类型定义中;
Example1:
module test(addr,read,write,datain,dataout)
input[7:0]  datain;
input[15:0] addr;
input       read,write;
output[7:0] dataout;  //要这样定义端口的位宽!
wire addr,read,write,datain;
reg  dataout;

Example2:
module test(addr,read,write,datain,dataout)
input  datain,addr,read,write;
output dataout;
wire[15:0] addr;
wire[7:0]  datain;
wire       read,write;
reg[7:0]   dataout;   // 不要这样定义端口的位宽!!

2、端口的I/O与数据类型的关系:
module内部     module外部
input              wire          wire或reg
output           wire或reg         wire
inout              wire            wire

3、assign语句的左端变量必须是wire;直接用"="给变量赋值时左端变量必须是reg!
Example:
assign a=b; //a必须被定义为wire!!
********
begin
a=b; //a必须被定义为reg!
end

在Verilog中有二种类型的内部信号用得比较多,它们是reg和wire。它们具有不同的功能。wire是线网形变量,它不能存储值,必须受到驱动器或者连续赋值语句的驱动。reg是数据存储单元的抽象,通过赋值语句可以改变寄存器存储的值,其作用与改变触发器存储的值相当。所有端口都有一个名称相同且声明为wire的信号。因此连线line被声明为wire不是必要的。reg会保持上次的赋值,因此不需要每次都进行驱动。wire型信号用于异步逻辑,有时也用来连接信号。因为 reg可以保持上次的值,因此输入不能被声明为reg类型。在Verilog模块中可以在任何时候异步地将输入改变为任何事件。reg和wire的主要区别是,reg类型的信号只能在过程块(后面会谈到)中赋值,而wire类型的信号只能在过程块外赋值。这两种信号类型都可以出现在过程块内部和外部的赋值运算符右边。 使用关键字reg并不一定意味着编译器会创建一个寄存器,理解这一点是非常重要的。

四、敏感变量的描述完备性
Verilog中,用always块设计组合逻辑电路时,在赋值表达式右端参与赋值的所有信号都必须在 always @(敏感电平列表)中列出,always中if语句的判断表达式必须在敏感电平列表中列出。如果在赋值表达式右端引用了敏感电平列表中没有列出的信号,在综合时将会为没有列出的信号隐含地产生一个透明锁存器。这是因为该信号的变化不会立刻引起所赋值的变化,而必须等到敏感电平列表中的某一个信号变化时,它的作用才表现出来,即相当于存在一个透明锁存器,把该信号的变化暂存起来,待敏感电平列表中的某一个信号变化时再起作用,纯组合逻辑电路不可能作到这一点。综合器会发出警告。
Example1:
input a,b,c;
reg e,d;
always @(a or b or c)
begin
e=d&a&b; /*d没有在敏感电平列表中,d变化时e不会立刻变化,直到a,b,c中某一个变化*/
d=e|c;
end

Example2:
input a,b,c;
reg e,d;
always @(a or b or c or d)
begin
e=d&a&b; /*d在敏感电平列表中,d变化时e立刻变化*/
d=e |c;
end
Verilog中用于上升沿和下降沿的关键字分别是posedge和negedge。这二个关键字经常被用于敏感列表。

五、条件的描述完备性
如果if语句和case语句的条件描述不完备,也会造成不必要的锁存器。
Example1:
if (a==1'b1) 
q=1'b1;//如果a==1'b0,q=? q将保持原值不变, 生成锁存器!

Example2:
if (a==1'b1) 
q=1'b1;
else         
q=1'b0;//q有明确的值, 不会生成锁存器!

Example3:
reg[1:0] a,q;
....
case (a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;//如果a==2'b10或a==2'b11,q=? q将保持原值不变, 锁存器!
endcase

Example4:
reg[1:0] a,q;
....
case (a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;
default: q=2'b00;//q有明确的值. 不会生成锁存器!

endcase

六、描述的规范性
以触发器为例说明描述的规范性
1、无置位/清零的时序逻辑
always @( posedge CLK)
begin
Q<=D;
end
2、有异步置位/清零的时序逻辑
异步置位/清零是与时钟无关的,当异步置位/清零信号到来时,触发器的输出立即被置为1或0,不需要等到时钟沿到来才置位/清零。所以,必须要把置位/清零信号   列入always块的事件控制表达式。
always @( posedge CLK or negedge RESET)
begin
if (!RESET)
Q=0;
else
Q<=D;
end
3、有同步置位/清零的时序逻辑
同步置位/清零是指只有在时钟的有效跳变时刻置位/清零,才能使触发器的输出分别转换为1或0。所以,不要把置位/清零信号列入always块的事件控制表达式。但是必须在always块中首先检查置位/清零信号的电平。
always @( posedge CLK )
begin
if (!RESET)
Q=0;
else
Q<=D;
end

七、非阻塞赋值和阻塞赋值
always块中的赋值运算符与以关键字assign开头的连续赋值语句中用到的运算符不一样。"<="运算符用于非阻塞性(nonblocking)赋值,而"="运算符用于阻塞性(blocking)赋值。在一组阻塞性赋值语句中,在下一个阻塞性赋值语句执行前需要计算并赋值第一个赋值语句。这一过程就象C语言中语句的顺序执行。而非阻塞语句在执行时,所有赋值语句的右边被同时计算和赋值,在always块结束后才完成赋值操作。连续赋值语句必须使用阻塞赋值语句(否则编译器会报错)。 
为了减少代码出错的概率,建议在顺序逻辑(例如希望以寄存器方式实现的逻辑)always块中的所有赋值语句使用非阻塞性赋值语句。大多数always块应该使用非阻塞性赋值语句。如果always块都是组合逻辑,那么就需要使用阻塞性赋值语句。

现列举八条“非阻塞赋值”和“阻塞赋值”指导方针,谨遵这些方针可以帮助Verilog设计者减少所遇到的90-100%的Verilog竞争:
1: 当为时序逻辑建模,使用“非阻塞赋值”。
2: 当为锁存器(latch)建模,使用“非阻塞赋值”。
3: 当用always块为组合逻辑建模,使用“阻塞赋值”
4: 当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。
5: 不要在同一个always块里面混合使用“阻塞赋值”和“非阻塞赋值”。
6: 不要在两个或两个以上always块里面对同一个变量进行赋值。
7: 使用$strobe以显示已被“非阻塞赋值”的值。
8: 不要使用#0延迟的赋值。

八、其他一些设计规范和原则
1:不使用初始化语句,用复位脉冲初始化信号和变量。
2:不使用延时语句;
3:不使用循环次数不确定的语句,如:forever,while等;
4:尽量采用同步方式设计电路;
5:尽量采用行为语句完成设计;
6:always过程块描述组合逻辑,应在敏感信号表中列出所有的输入信号;
7:所有的内部寄存器都应该可以被复位;避免使用内部生成的异步置位/清零信号,内部生成的置位/清零信号会引起测试问题。使某些输出信号被置位或清零,无法正常测试。
8:用户自定义原件(UDP元件)是不能被综合的。
9: if...else if ... else 语句是有优先级的,一般说来第一个if的优先级最高,最后一个else的优先级最低。 而case语句是"平行"的结构,所有的case的条件和执行都没有“优先级”。而建立优先级结构会消耗大量的组合逻辑,所以如果能够使用case语句的地方,尽量使用case替换if...else结构。
10: 状态机的一般设计原则,Biary, gray-code 编码使用最少的触发器,较多的组合逻辑。而one-hot编码反之。所以CPLD多使用GRAY-CODE, 而FPGA多使用ONE-HOT编码。另一方面,小型设计使用GRAY-CODE和BINARY编码更有效,而大型状态机使用ONE-HOT更有效。
11:fpga设计中不要使用门时钟,内部生成的时钟称为门生时钟(gated clock)。时钟信号必须连接到全局时钟管脚上。
12:不要使用内部三态信号,否则增加功耗。
13:避免使用负延触发的双稳态多谐振荡器(flip flop)。
14:不要在代码中使用buffer 类型的端口读取输出数据;要使用out 类型,再增加另外变量或信号,以获取输出值。这是因为buffer 类型的端口不能连接到其他类型的端口上,因此buffer 类型就会在整个设计的端口中传播下去。
15:对变量要先读后写;如果先写后读,就会产生长的组合逻辑和锁存器(或寄存器)。这是因为变量值是立即获取的。

硬件描述语言Verilog设计经验总结相关推荐

  1. 第三章 硬件描述语言verilog(一)

    文章目录 第三章 硬件描述语言verilog 第1节 Verilog语言的历史 第2节 综合和仿真 2.1 综合 2.2 仿真 2.3 可综合设计 第3节 模块结构 3.1 模块介绍 3.2 模块名和 ...

  2. (一)硬件描述语言verilog

    问题总结区 1.如何理解 module ..... endmodule ? module 指模块是verilog 的一个基本单元,这个基本单元可以是描述一个简单的求和行为,也可以用来表达一个功能器件( ...

  3. 硬件描述语言Verilog学习(二)

  4. 硬件描述语言Verilog学习(五)

  5. 硬件描述语言Verilog学习(三)

  6. 硬件描述语言Verilog学习(一)

  7. [从零开始学习FPGA编程-9]:快速入门篇 - 操作步骤2-1- 硬件电路图形化描述与文本硬件描述语言Verilog HDL与VHDL语言以及比较

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  8. Verilog硬件描述语言

    硬件描述语言HDL是具有特殊结构能够对硬件逻辑电路的功能进行描述的一种高级编程语言,这种特殊结构能够: 描述电路的连接 描述电路的功能 在不同抽象级上描述电路 描述电路的时序 表达具有并行性 HDL主 ...

  9. 例说Verilog HDL和VHDL区别,助你选择适合自己的硬件描述语言

    如果你搜索Verilog和VHDL的区别,你会看到很多讨论这场HDL语言战争的区别页面,但大多数都很简短,没有很好地举例说明,不方便初学者或学生理解. Verilog和VHDL之间的区别将在本文中通过 ...

最新文章

  1. Ubuntu Apache 服务之 PHP 配置
  2. php 实现进制相互转换
  3. 首个由国内发起的分布式消息领域的国际标准OpenMessaging一周年回顾
  4. SSM综合练习表结构介绍
  5. python的setting怎么找_Python的Django框架中settings文件的部署建议
  6. GitHub动作简介
  7. fisher线性判别算法python_干货|机器学习算法之线性判别分析
  8. xtarbackup 安装
  9. java B2B2C springmvc mybatis电子商务平台源码-------zuul网关实现
  10. Mapped Statements collection already contains value for*
  11. IPv6-IPv4过渡技术详解及配置实例
  12. Elasticsearch6.3.0环境安装
  13. 从表象到本质,包你一文看懂NFT
  14. Fatal signal 11 (SIGSEGV) at 0x00000004 (code=1), thread 261 (servicemanager)错误
  15. uni-app 背景图片处理
  16. php获取QQ音乐直链,~~~获取qq音乐外链方法+源码~~~
  17. 【一起入门NLP】中科院自然语言处理作业四:RNN+Attention实现Seq2Seq中英文机器翻译(Pytorch)【代码+报告】
  18. LeetCode 605[Python]. 种花问题 假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
  19. 30套免费的响应式 HTML5 CSS3 模板下载
  20. 使用 Symfony DomCrawler 进行爬虫 已解决

热门文章

  1. 炸弹人问题(简单版)
  2. linux edb 运行不了,运行 Linux 的 IBM Power Systems 上的 EDB Postgres Advanced Server 9.5 入门...
  3. 寻找身高相近的小朋友
  4. 油猴子(greasemonkey)初步体验心得
  5. leetcode系列374-猜数字大小
  6. leetcode 546. 移除盒子 —— 动态规划
  7. 《动态壁纸 : 手机壁纸大全》用户协议
  8. 手把手教你如何给视频快速消音并添加背景音乐
  9. 渗透测试工具:跨站脚本漏洞检测---Xsser
  10. mac os 安装完整版opencv (with qt )