minor update to post josh-verilog

This commit is contained in:
2023-07-09 10:52:38 +08:00
parent 5a9e7370ef
commit 8c57cf87b9
5 changed files with 871 additions and 287 deletions
+785 -201
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -12,7 +12,7 @@
"version": "6.3.0" "version": "6.3.0"
}, },
"dependencies": { "dependencies": {
"@next-theme/plugins": "^8.17.0", "@next-theme/plugins": "^8.17.1",
"hexo": "^6.3.0", "hexo": "^6.3.0",
"hexo-abbrlink": "^2.2.1", "hexo-abbrlink": "^2.2.1",
"hexo-deployer-git": "^4.0.0", "hexo-deployer-git": "^4.0.0",
@@ -29,11 +29,11 @@
"hexo-related-posts": "^1.5.1", "hexo-related-posts": "^1.5.1",
"hexo-renderer-ejs": "^2.0.0", "hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-pandoc": "^0.4.0", "hexo-renderer-pandoc": "^0.4.0",
"hexo-renderer-stylus": "^2.1.0", "hexo-renderer-stylus": "^3.0.0",
"hexo-server": "^3.0.0", "hexo-server": "^3.0.0",
"hexo-tag-cloud": "2.1.*", "hexo-tag-cloud": "2.1.*",
"hexo-theme-landscape": "^1.0.0", "hexo-theme-landscape": "^1.0.0",
"hexo-theme-next": "^8.17.0", "hexo-theme-next": "^8.17.1",
"hexo-word-counter": "^0.1.0" "hexo-word-counter": "^0.1.0"
} }
} }
+16 -16
View File
@@ -20,7 +20,7 @@ toc:
expand_all: true expand_all: true
max_depth: 4 max_depth: 4
abbrlink: 460433dd abbrlink: 460433dd
description: 本文阐述了 HDL 语言/设计方法的基本概念。主要介绍了数字系统建模方法的演变,引入了 HDL 语言的基本概念,对 Verilog HDL 和 VHDL、Verilog HDL 和 C 的联系与区别进行了说明,在最后引入了 HDL 的设计和验证流程,并对各个流程进行了简单介绍。 description: 本文阐述了 HDL 语言/设计方法的基本概念。主要介绍了数字系统建模方法的演变,引入了 HDL 语言的基本概念,对 Verilog HDL 和 VHDL、Verilog HDL 和 C 的联系与区别进行了说明,最后引入了 HDL 的设计和验证流程,并对各个流程进行了简单介绍。
--- ---
# 1. 设计方法的变迁<a id="toc.1"></a> # 1. 设计方法的变迁<a id="toc.1"></a>
@@ -29,19 +29,19 @@ description: 本文阐述了 HDL 语言/设计方法的基本概念。主要介
<!-- more --> <!-- more -->
随着数字电路系统的不断发展,系统的逻辑复杂度与规模日益增加,数字系统的设计方法也随之不断演进。早期简单的门逻辑设计阶段,EDA 工具应用范围十分有限,工程师们习惯于使用**{% label prime@卡诺图 %}**简化设计,然后通过面包板等实验系统验证设计;系统相对复杂后,工程师们借助 EDA 工具通过原理图描述数字系统。 随着数字电路系统的不断发展,系统的逻辑复杂度与规模日益增加,数字系统的设计方法也随之不断演进。在早期简单的门逻辑设计阶段,EDA(Electronic Design Automation,电子设计自动化)工具应用范围十分有限,工程师们习惯于使用**{% label prime@卡诺图 %}**简化设计,然后通过面包板等实验系统验证设计;系统相对复杂后,工程师们借助 EDA 工具通过原理图描述数字系统。
{% note default %} {% note default %}
原理图由元件库中的元件构成,使用 EDA(Electronic Design Automation,电子设计自动化)工具可以对原理图进行仿真并分析其性能。 原理图由元件库中的元件构成,使用 EDA 工具可以对原理图进行仿真并分析其性能。
{% endnote %} {% endnote %}
当数字系统发展到 ASIC 与 PLD(Programmable Logic Device,可编程逻辑器件) 设计阶段后,原理图不利于移植、维护费时费力等缺点逐步显现,这时需要抽象度更高、更灵活的设计方式 —— HDL(Hardware Description Language,硬件描述语言)。 当数字系统发展到 ASIC 与 PLD(Programmable Logic Device,可编程逻辑器件)设计阶段后,原理图不利于移植、维护费时费力等缺点逐步显现,这时需要抽象度更高、更灵活的设计方式 —— HDL(Hardware Description Language,硬件描述语言)。
使用 HDL 语言,可以从算法、系统级(System Level)、功能模块级(Functional Model Level)、行为级(Behavioral Level)、寄存器传输级(RTL, Register Transfer Level)、门级(Gate Level)到开关级(Switch Level)等不同层次描述数字电路系统,然后通过 EDA 工具综合、仿真并实现该系统。可以说 HDL 语言的出现是数字系统设计方法的一个重大飞跃。 使用 HDL 语言,可以从算法、系统级(System Level)、功能模块级(Functional Model Level)、行为级(Behavioral Level)、寄存器传输级(RTL, Register Transfer Level)、门级(Gate Level)到开关级(Switch Level)等不同层次描述数字电路系统,然后通过 EDA 工具综合、仿真并实现该系统。可以说 HDL 语言的出现是数字系统设计方法的一个重大飞跃。
数字电路系统设计方法的另一个重大飞跃是随着 EDA 工具的不断推陈出新发生的。早期 ASIC 和 PLD 设计时,人们需要直接描述 CMOS 的开关电路或门级电路,其设计量庞大,仿真速度也非常慢,像当今系统门数量为千万门级的 FPGA 用开关级或门级方法描述在当时是不可想象的。这时人们就希望能够使用 HDL 直接从更高的层次描述电路,然后使用 EDA 工具自动将高层次的 HDL 电路描述解析到门级,这些将大大节约设计与仿真时间,这个**{% label prime@从高层次的电路描述通过 EDA 工具解析到门级等低层次的电路描述的过程就叫“综合”(Synthesize),或者逻辑综合 %}**。 数字电路系统设计方法的另一个重大飞跃是随着 EDA 工具的不断推陈出新发生的。早期 ASIC 和 PLD 设计时,需要直接描述 CMOS 的开关电路或门级电路,其设计量庞大,仿真速度也非常慢,用开关级或门级方法描述如当今门数量为千万门级的 FPGA 在当时是不可想象的。这时人们就希望能够使用 HDL 直接从更高的层次描述电路,然后使用 EDA 工具自动将高层次的 HDL 电路描述解析到门级,这些将大大节约设计与仿真时间,这个**{% label prime@从高层次的电路描述通过 EDA 工具解析到门级等低层次的电路描述的过程就叫“综合”(Synthesize),或者逻辑综合 %}**。
{% note default %} {% note default %}
@@ -85,27 +85,27 @@ Verilog 语言是根据 C 语言发明而来的,因此 Verilog 具备了 C 语
1. C 语言与 Verilog 的最大区别 1. C 语言与 Verilog 的最大区别
C 语言与 Verilog 的最大区别在于 C 缺乏硬件描述的 3 个基本概念: C 语言与 Verilog 的最大区别在于 C 缺乏硬件描述的 3 个基本概念:
- **{% label primary @互连(connectivity) %}**:硬件系统中,互连是非常重要的组成部分,而在 C 语言中并没有直接可以用来表示模块间互连的变量;而 Verilog 的 `wire` 型变量配合一些驱动结构能有效地描述网线的互连。 - **{% label primary @互连(connectivity) %}**:硬件系统中,互连是非常重要的组成部分,而在 C 语言中并没有直接可以用来表示模块间互连的变量;而 Verilog 的 `wire` 型变量配合一些驱动结构能有效地描述网线的互连。
- **{% label primary @并发(concurrency) %}**:C 语言天生是**串行**的,不能描述硬件之间并发的特性,C 语言编译后,其机器指令在 CPU 的高速缓冲队列中基本是顺序执行;而 Verilog 可以有效地描述并行的硬件系统,硬件系统比软件系统速度快、实时性高的一个重要原因就是硬件系统中**各个单元的运算是独立的,信号流是并行的**。 - **{% label primary @并发(concurrency) %}**:C 语言天生是**串行**的,不能描述硬件之间并发的特性,C 语言编译后,其机器指令在 CPU 的高速缓冲队列中基本是顺序执行;而 Verilog 可以有效地描述并行的硬件系统,硬件系统比软件系统速度快、实时性高的一个重要原因就是硬件系统中**各个单元的运算是独立的,信号流是并行的**。
- **{% label primary @时间(time) %}**:C 程序运行的时候,没有一个严格的时间概念,程序运行的时间长短取决于处理器本身的性能;而 Verilog 语言本身定义了绝对和相对的时间度量,在仿真时可以通过时间度量与周期关系描述信号直接的时间关系。 - **{% label primary @时间(time) %}**:C 程序运行的时候,没有一个严格的时间概念,程序运行的时间长短取决于处理器本身的性能;而 Verilog 语言本身定义了绝对和相对的时间度量,在仿真时可以通过时间度量与周期关系描述信号直接的时间关系。
2. HDL 语言的本质 2. HDL 语言的本质
硬件描述语言(HDL)同软件语言(如 C、C++ 等)是有本质区别的。Verilog 作为硬件描述语言,**它的本质作用在于描述硬件**。Verilog 虽然采用了 C 语言形式,但是它的最终描述结果是芯片内部的实际电路。所以评判一段 HDL 代码优劣的最终标准是其描述并实现的硬件电路的性能(包括面积和速度两个方面)。评价一个设计的代码水平较高,仅仅是说这个设计由硬件向 HDL 代码这种表现形式转换得更流畅、合理。而一个设计的最终性能更大程度上取决于设计工程师所构想的硬件实现方案的效率以及合理性。 硬件描述语言(HDL)同软件语言(如 C、C++ 等)是有本质区别的。Verilog 作为硬件描述语言,**它的本质作用在于描述硬件**。Verilog 虽然采用了 C 语言形式,但是它的最终描述结果是芯片内部的实际电路。所以评判一段 HDL 代码优劣的最终标准是其描述并实现的硬件电路的性能(包括**面积**和**速度**两个方面)。评价一个设计的代码水平较高,仅仅是说这个设计由硬件向 HDL 代码这种表现形式转换得更流畅、合理。而一个设计的最终性能更大程度上取决于设计工程师所构想的硬件实现方案的效率以及合理性。
{% note warning %} {% note warning %}
初学者,特别是由软件转行的初学者,片面追求代码的整洁、简短,这是错误的,是与评价 HDL 的标准背道而驰的。正确的编写代码的方法是,首先要做到对所需实现的硬件电路“胸有成竹”,对该部分硬件的结构与连接十分清晰,然后再用适当的 HDL 语句表达出来即可。 初学者,特别是由软件转行的初学者,片面追求代码的整洁、简短,这是错误的,是与评价 HDL 的标准背道而驰的。正确的编写代码的方法是,首先要做到对所需实现的硬件电路“胸有成竹”,对该部分硬件的结构与连接十分清晰,然后再用适当的 HDL 语句表达出来即可。
{% endnote %} {% endnote %}
3. Verilog 与 C 的结合 3. Verilog 与 C 的结合
Verilog 毕竟是硬件描述语言,在抽象层次上比 C 语言要差一些,语法不如 C 灵活,例如文件输入和输出方面,Verilog 的功能显然不如 C。为了克服 Verilog 高级抽象的缺陷,Verilog 的设计者们发明了 PLI。PLI 可以在仿真器中将 C 语言的程序和 Verilog 的程序互相通信,或者在 Verilog 中调用 C 语言的函数库,这样就大大扩展了 Verilog 语言的灵活性和高层次抽象的能力。开发时,一方面,硬件设计者使用 Verilog 进行硬件建模;另一方面,验证工程师却常常使用 C 来编写测试向量,然后通过 Verilog 的 PLI 将 Verilog 和 C 联系起来。这样,C 语言就很好地弥补了 Verilog 高层次建模的缺陷。 Verilog 毕竟是硬件描述语言,在抽象层次上比 C 语言要差一些,语法不如 C 灵活,例如文件输入和输出方面,Verilog 的功能显然不如 C。为了克服 Verilog 高级抽象的缺陷,Verilog 的设计者们发明了 PLI(Programming Language Interface)。PLI 可以在仿真器中将 C 语言的程序和 Verilog 的程序互相通信,或者在 Verilog 中调用 C 语言的函数库,这样就大大扩展了 Verilog 语言的灵活性和高层次抽象的能力。开发时,一方面,硬件设计者使用 Verilog 进行硬件建模;另一方面,验证工程师却常常使用 C 来编写测试向量,然后通过 Verilog 的 PLI 将 Verilog 和 C 联系起来。这样,C 语言就很好地弥补了 Verilog 高层次建模的缺陷。
# 3. HDL 的设计与验证流程<a id="toc.3"></a> # 3. HDL 的设计与验证流程<a id="toc.3"></a>
@@ -155,8 +155,8 @@ RTL 级综合指 **{% label prime@将 RTL 级 HDL 语言翻译成由与、或、
# 参考文献 # 参考文献
EDA 先锋工作室. *轻松成为设计高手——Verilog HDL 实用精解.* 北京航空航天大学出版社, 2012. EDA 先锋工作室. _轻松成为设计高手——Verilog HDL 实用精解._ 北京航空航天大学出版社, 2012.
[Part 3——描述方式和设计层次的 5. 设计层次]: https://josh-gao.top/posts/fd117896.html#toc.5 [Part 3——描述方式和设计层次的 5. 设计层次]: https://josh-gao.top/posts/fd117896.html#toc.5
[^1]: 最新的 Verilog HDL标准为 IEEE 1364-2005。 [^1]: 最新的 Verilog HDL标准为 [IEEE 1364-2005](https://ieeexplore.ieee.org/document/1620780)。
+64 -64
View File
@@ -31,13 +31,13 @@ description: 本文从一个 Verilog 用例出发,对 Verilog 语言的语法
<!-- more --> <!-- more -->
最近几年,随着 IP核 市场的逐渐兴起,许多设计者逐渐意识到**利用现有的 IP核可以帮助节约设计成本、减少设计周期**,有许多设计工程师,甚至希望所有的设计模块都使用现成的模块,自己仅仅开发一些简单的粘合逻辑。这就有点像电路板设计的过程,工程师将各种芯片集成到一块电路板上,自己完成这些芯片间的互连和一些简单的 CPLD 逻辑设计,以及对微处理器的编程。使用现有的 IP 来搭建系统实际上也是一种**自底向上**(Bottom-Up)的设计方法。 最近几年,随着 IP 核市场的逐渐兴起,许多设计者逐渐意识到**利用现有的 IP 核可以帮助节约设计成本、减少设计周期**,有许多设计工程师,甚至希望所有的设计模块都使用现成的模块,自己仅仅开发一些简单的粘合逻辑。这就有点像电路板设计的过程,工程师将各种芯片集成到一块电路板上,自己完成这些芯片间的互连和一些简单的 CPLD 逻辑设计,以及对微处理器的编程。使用现有的 IP 来搭建系统实际上也是一种**自底向上**(Bottom-Up)的设计方法。
从以上描述可以看出,设计硬件电路时,这两种设计方法都有可能采用。Verilog HDL 可以完全支持这两种设计方法。 从以上描述可以看出,设计硬件电路时,这两种设计方法都有可能采用。Verilog HDL 可以完全支持这两种设计方法。
- 在门级的设计中,用户可以直接实例化 Verilog 语言中的门级原语构建系统; - 在门级的设计中,用户可以直接实例化 Verilog 语言中的门级原语构建系统;
- 如果需要描述硬件的行为,可以使用 Verilog 的行为级描述功能; - 如果需要描述硬件的行为,可以使用 Verilog 的行为级描述功能;
- 如果要使用 IP核 ,只要在设计中直接实例化 IP核 即可。 - 如果要使用 IP 核,只要在设计中直接实例化 IP 核即可。
EDA 行业的先行者们发明了 Verilog 硬件描述语言,其最根本的目的就是用 Verilog 来描述硬件的行为,但是有的描述是不需要实现为硬件电路的。 EDA 行业的先行者们发明了 Verilog 硬件描述语言,其最根本的目的就是用 Verilog 来描述硬件的行为,但是有的描述是不需要实现为硬件电路的。
@@ -63,13 +63,13 @@ EDA 行业的先行者们发明了 Verilog 硬件描述语言,其最根本的
**这些电路单元都是同时并行工作的,相互之间并没有先后顺序关系,这一点与软件设计程序很不一样。** **这些电路单元都是同时并行工作的,相互之间并没有先后顺序关系,这一点与软件设计程序很不一样。**
下面具体分析 [HelloVlog 模块](#HelloVlog) 的电路功能。源代码如下。 下面具体分析 [HelloVlog 模块](#HelloVlog) 的电路功能,代码如下。
<a id="HelloVlogCode"></a> <a id="HelloVlogCode"></a>
``` verilog HelloVlog.v ``` verilog HelloVlog.v
// 编译指令, 定义时间单位和时间精度 // 编译指令, 定义时间单位和时间精度
`timescale 1ns/100p // 每个时间单位是1ns, 仿真精度是100ps `timescale 1ns / 100ps // 每个时间单位是1ns, 仿真精度是100ps
// module名 + 端口列表 // module名 + 端口列表
module HelloVlog( clk, rst_n, A_in, B_in, sel, A_xor_out, B_xor_out ); module HelloVlog( clk, rst_n, A_in, B_in, sel, A_xor_out, B_xor_out );
@@ -144,60 +144,60 @@ endmodule
1. 二选一多路选择器 1. 二选一多路选择器
对于 `MUX21` 这样二选一的电路,将采用如下的数据流描述(assign语句): 对于 `MUX21` 这样二选一的电路,将采用如下的数据流描述(assign语句):
``` verilog HelloVlog.v ``` verilog HelloVlog.v
assign #3 result = sel ? B_in : A_in; assign #3 result = sel ? B_in : A_in;
``` ```
`assign` 是 Verilog 中的关键词,用它赋值的语言称为**连续赋值语句**。 `assign` 是 Verilog 中的关键词,用它赋值的语言称为**连续赋值语句**。
如果 `sel`为真(1),则选择 `B_in`,否则将选择 `A_in`,而 `#3` 表示经过 3 个延时单位,再将选择结果赋值给 `result`,这也模拟了组合逻辑的延时。由于在[代码](#HelloVlogCode)最开头已经使用 Verilog 的编译指令将延时单位定义为 1ns(`timescale 1ns/100ps`),因此这里的 `#3` 代表 3ns 的延时。 如果 `sel`为真(1),则选择 `B_in`,否则将选择 `A_in`,而 `#3` 表示经过 3 个延时单位,再将选择结果赋值给 `result`,这也模拟了组合逻辑的延时。由于在[代码](#HelloVlogCode)最开头已经使用 Verilog 的编译指令将延时单位定义为 1ns(`timescale 1ns/100ps`),因此这里的 `#3` 代表 3ns 的延时。
2. 2 - 4 译码器 2. 2 - 4 译码器
关于实现 2 - 4 译码器,则采用了如下的描述: 关于实现 2 - 4 译码器,则采用了如下的描述:
``` verilog HelloVlog.v ``` verilog HelloVlog.v
always @(result) begin always @(result) begin
case(result) case(result)
2'b00: begin 2'b00: begin
{eq3, eq2, eq1, eq0} = #2 4'b0001; {eq3, eq2, eq1, eq0} = #2 4'b0001;
$display ("At time %t-", $time, "eq0 = 1"); $display ("At time %t-", $time, "eq0 = 1");
end end
// ... // ...
default: ; default: ;
endcase endcase
end end
``` ```
这里采用了另一种描述方式:用 `always` 语句来描述电路的行为。通过 `case` 判断 `result` 的值来决定 `eq0` ~ `eq3` 的值。同样,也采用 `#2` 来模拟组合逻辑的延时。`always` 和 `case` 也是 Verilog 中的关键词。这样的描述方法称之为**行为描述**,它侧重于描述电路的行为。 这里采用了另一种描述方式:用 `always` 语句来描述电路的行为。通过 `case` 判断 `result` 的值来决定 `eq0` ~ `eq3` 的值。同样,也采用 `#2` 来模拟组合逻辑的延时。`always` 和 `case` 也是 Verilog 中的关键词。这样的描述方法称之为**行为描述**,它侧重于描述电路的行为。
``` verilog HelloVlog.v ``` verilog HelloVlog.v
{eq3, eq2, eq1, eq0} = #2 4'b0001; {eq3, eq2, eq1, eq0} = #2 4'b0001;
``` ```
该语句表示将 `4'b0001` 赋值给 `eq3` ~ `eq0` 合并成的 4 位变量。`{}` 是 Verilog 的合并符号。 该语句表示将 `4'b0001` 赋值给 `eq3` ~ `eq0` 合并成的 4 位变量。`{}` 是 Verilog 的合并符号。
3. 异或门 3. 异或门
对于 `A_xor_wire` 和 `XOR_B` 的两个完全一样的异或门,也采用了两种不同的描述方式: 对于 `A_xor_wire` 和 `XOR_B` 的两个完全一样的异或门,也采用了两种不同的描述方式:
``` verilog HelloVlog.v ``` verilog HelloVlog.v
assign #1 A_xor_wire = eq0 ^ eq1; assign #1 A_xor_wire = eq0 ^ eq1;
``` ```
和 和
``` verilog HelloVlog.v ``` verilog HelloVlog.v
xor #1 XOR_B(B_xor_wire, eq2, eq3); xor #1 XOR_B(B_xor_wire, eq2, eq3);
``` ```
`xor` 是 Verilog 中自带的基本逻辑门原语。这里相当于调用了该 `xor` 门。而 `B_xor_wire`、`eq2` 和 `eq3` 是代入到 `xor` 门中的参数。`eq2` 和 `eq3` 是输入,`B_xor_wire` 是输出。这里 `B_xor_wire` 是 `eq2` 和 `eq3` 相异或的结果。 `xor` 是 Verilog 中自带的基本逻辑门原语。这里相当于调用了该 `xor` 门。而 `B_xor_wire`、`eq2` 和 `eq3` 是代入到 `xor` 门中的参数。`eq2` 和 `eq3` 是输入,`B_xor_wire` 是输出。这里 `B_xor_wire` 是 `eq2` 和 `eq3` 相异或的结果。
在 Verilog 中,**将调用其他功能模块(包括 Verilog 的内嵌基本逻辑门)称为“实例化(Instantiate)”**。实例化**类似**于软件设计中的调用,但不能简单理解为软件中的调用。软件调用过程是顺序执行的,而实例化的硬件电路在设计中是独立于其他功能块,并行运行的。 在 Verilog 中,**将调用其他功能模块(包括 Verilog 的内嵌基本逻辑门)称为“实例化(Instantiate)”**。实例化**类似**于软件设计中的调用,但不能简单理解为软件中的调用。软件调用过程是顺序执行的,而实例化的硬件电路在设计中是独立于其他功能块,并行运行的。
这种**在模块中实例化其他功能模块**的描述方式被称之为**结构化描述**。 这种**在模块中实例化其他功能模块**的描述方式被称之为**结构化描述**。
## 2.2. 3 种描述方法<a id="toc.2.2"></a> ## 2.2. 3 种描述方法<a id="toc.2.2"></a>
@@ -217,44 +217,44 @@ endmodule
在 [Part 3——描述方式和设计层次][]中会详细介绍 Verilog 语言中的这 3 种描述方式。 在 [Part 3——描述方式和设计层次][]中会详细介绍 Verilog 语言中的这 3 种描述方式。
# 3. Verilog 的基本词法<> # 3. Verilog 的基本词法
1. Verilog HDL 是一种**大小写敏感**的语言,这一点与 VHDL 不同,因此在书写的时候要格外注意。在 Verilog 语言中,**所有的关键字(又叫保留字)都为小写**。Verilog 的内部信号名(或称为标识符)使用大写和小写都可以。标识符可以是字母、数字、`$`(美元符号)和 `_`(下划线)任意组合,只要**第一个字符是字母或者下划线**即可。 1. Verilog HDL 是一种**大小写敏感**的语言,这一点与 VHDL 不同,因此在书写的时候要格外注意。在 Verilog 语言中,**所有的关键字(又叫保留字)都为小写**。Verilog 的内部信号名(或称为标识符)使用大写和小写都可以。标识符可以是字母、数字、`$`(美元符号)和 `_`(下划线)任意组合,只要**第一个字符是字母或者下划线**即可。
{% note warning %} {% note warning %}
因为 Verilog HDL 对大小写敏感,因此养成良好的信号定义习惯非常重要,否则容易因为大小写不同造成信号的歧义。推荐的信号定义习惯为:**所有信号和网线名均小写,用下划线分割单词,而宏变量全部用大写字母。** 因为 Verilog HDL 对大小写敏感,因此养成良好的信号定义习惯非常重要,否则容易因为大小写不同造成信号的歧义。推荐的信号定义习惯为:**所有信号和网线名均小写,用下划线分割单词,而宏变量全部用大写字母。**
{% endnote %} {% endnote %}
2. 在上述[代码](#HelloVlogCode)中,用双反斜线 `//` 表示注释。另外,还有一种注释方式,用 `/* ...... */` 来表示。所不同的是前者为单行注释,而后者将 `/*` 和 `*/` 之间的内容全部看作注释内容。 2. 在上述[代码](#HelloVlogCode)中,用双反斜线 `//` 表示注释。另外,还有一种注释方式,用 `/* ...... */` 来表示。所不同的是前者为单行注释,而后者将 `/*` 和 `*/` 之间的内容全部看作注释内容。
{% note info %} {% note info %}
通常,注释的内容只是作者为了增强代码的可读性而增加的内容,对整个代码的功能没有任何影响。不过,在一些工具中,尤其是逻辑综合工具,定义了一些特殊的指令,用于控制工具编译过程。这些指令也是以注释的方式出现的。例如: 通常,注释的内容只是作者为了增强代码的可读性而增加的内容,对整个代码的功能没有任何影响。不过,在一些工具中,尤其是逻辑综合工具,定义了一些特殊的指令,用于控制工具编译过程。这些指令也是以注释的方式出现的。例如:
``` verilog ``` verilog
module bl_box(out, data, clk) /* synthesis syn_black_box */; module bl_box(out, data, clk) /* synthesis syn_black_box */;
``` ```
在 `module bl_box` 的声明处有一行注释,用 `/* ...... */` 表示。它看起来是一个注释,实际上,是综合工具 Synplify 中的一个指令,指示 Synplify 将该模块看作一个黑盒(black_box),不处理模块内部的描述。 在 `module bl_box` 的声明处有一行注释,用 `/* ...... */` 表示。它看起来是一个注释,实际上,是综合工具 Synplify 中的一个指令,指示 Synplify 将该模块看作一个黑盒(black_box),不处理模块内部的描述。
{% endnote %} {% endnote %}
3. 在 Verilog 中,通常使用空格符、跳格符和换行符作为间隔。在书写代码的时候,适当运用间隔符可以提高代码的可读性。比如在声明 4 个 `reg` 型数据 `eq0~eq3` 时,可以采用上述[例子](#HelloVlogCode)中的方法: 3. 在 Verilog 中,通常使用空格符、跳格符和换行符作为间隔。在书写代码的时候,适当运用间隔符可以提高代码的可读性。比如在声明 4 个 `reg` 型数据 `eq0~eq3` 时,可以采用上述[例子](#HelloVlogCode)中的方法:
``` verilog HelloVlog.v ``` verilog HelloVlog.v
reg eq0, eq1, eq2, eq3; reg eq0, eq1, eq2, eq3;
``` ```
也可以用换行符将其分开: 也可以用换行符将其分开:
``` verilog ``` verilog
reg eq0; reg eq0;
reg eq1; reg eq1;
reg eq2; reg eq2;
reg eq3; reg eq3;
``` ```
4. 在verilog中,还有一些转义字符。比如 `\n` 表示换行符;`\t` 表示 Tab 键;防止引起歧义,就用 `\` 表示 `\` 符号本身等等。这里不再对 Verilog 的词法做过多的描述,更多可以参考 Verilog IEEE 国际标准([IEEE Std. 1364-2005][])。 4. 在verilog中,还有一些转义字符。比如 `\n` 表示换行符;`\t` 表示 Tab 键;防止引起歧义,就用 `\` 表示 `\` 符号本身等等。这里不再对 Verilog 的词法做过多的描述,更多可以参考 Verilog IEEE 国际标准([IEEE Std. 1364-2005][])。
@@ -345,7 +345,7 @@ Verilog 中的编译指令是从 C 语言中的“预处理指令”演变得来
在每一个 `module` 文件前面加上 `` ` `` 的编译指令,就可以保证该文件中的延时信息受其自身文件中的 `` `timescale`` 编译指令指导。**否则在编译过程中,该模块将沿用上一个** `` `timescale`` **的值,或者使用缺省值**。 在每一个 `module` 文件前面加上 `` ` `` 的编译指令,就可以保证该文件中的延时信息受其自身文件中的 `` `timescale`` 编译指令指导。**否则在编译过程中,该模块将沿用上一个** `` `timescale`` **的值,或者使用缺省值**。
在上述实例代码描述的 [HelloVlog](#HelloVlogCode) 模块中使用了一个`` `timescale 1ns/100ps`` 编译指令。其中 `1ns` 表示延时单位,`100ps` 表示时间精度,也就是编译器所能接收的最小仿真时间粒度。`` `timescale`` 编译指令在模块外部出现,并且影响后面模块中所有的时延值,直到遇到下一个 `` `timescale`` 或 `` `resetall``指令。 在上述实例代码描述的 [HelloVlog](#HelloVlogCode) 模块中使用了一个`` `timescale 1ns/100ps`` 编译指令。其中 `1ns` 表示延时单位,`100ps` 表示时间精度,也就是编译器所能接收的最小仿真时间粒度。`` `timescale`` 编译指令在模块外部出现,并且影响后面模块中所有的时延值,直到遇到下一个 `` `timescale`` 或 `` `resetall`` 指令。
比如语句: 比如语句:
@@ -357,7 +357,7 @@ assign #(1.16) A_xor_wire = eq0 ^ eq1;
## 5.2. `` `define`` 和 `` `undef`` ## 5.2. `` `define`` 和 `` `undef``
`` `define`` 用于定义宏。例如,首先定义一个总线宽度的宏为 16,然后利用这个宏定义一个宽度为 16 的 `reg`类型数据 `Data`,方法如下: `` `define`` 用于定义宏。例如,首先定义一个总线宽度的宏为 16,然后利用这个宏定义一个宽度为 16 的 `reg` 类型数据 `Data`,方法如下:
``` verilog ``` verilog
`define BUS_WIDTH 16 `define BUS_WIDTH 16
@@ -593,7 +593,7 @@ end
在下一小节中,将引入“驱动”和“赋值”两个概念,深入探讨两种变量的含义。 在下一小节中,将引入“驱动”和“赋值”两个概念,深入探讨两种变量的含义。
## 7.4. 驱动和赋值<a id>="toc.7.4"</a> ## 7.4. 驱动和赋值<a id="toc.7.4"></a>
为了更清楚地描述寄存器和线网变量的概念,将以上述[实例代码](#HelloVlogCode)中的语句来说明。首先,引入 Verilog 语言中两个重要的概念:驱动(Driving)和赋值(Assigning)。 为了更清楚地描述寄存器和线网变量的概念,将以上述[实例代码](#HelloVlogCode)中的语句来说明。首先,引入 Verilog 语言中两个重要的概念:驱动(Driving)和赋值(Assigning)。
@@ -687,7 +687,7 @@ parameter xor_delay = 4;
- `begin ... end`:顺序语句组; - `begin ... end`:顺序语句组;
- `fork ... join`:并行语句组。 - `fork ... join`:并行语句组。
在 `begin ... end` 中存在的语句,按照 Veilog 的语义,应该是顺序执行的。而在 `fork ... join` 中的语句,则是并行执行的。 在 `begin ... end` 中存在的语句,按照 Verilog 的语义,应该是顺序执行的。而在 `fork ... join` 中的语句,则是并行执行的。
相比较顺序运行的事物,并行的事物比较难以理解和建模。同时,用于仿真的计算机是串行执行的,而 Verilog 语言本身的语义是用计算机进行模拟的语义,是用一种串行的语义来模拟并行的硬件。 相比较顺序运行的事物,并行的事物比较难以理解和建模。同时,用于仿真的计算机是串行执行的,而 Verilog 语言本身的语义是用计算机进行模拟的语义,是用一种串行的语义来模拟并行的硬件。
@@ -178,7 +178,7 @@ assign #(4:5:6, 3:4:5) A_xor_wire = eq0 ^ eq1;
表示上升延时的 `min:typ:max` 为 `4:5:6`,下降延时的 `min:typ:max` 为 `3:4:5`。 表示上升延时的 `min:typ:max` 为 `4:5:6`,下降延时的 `min:typ:max` 为 `3:4:5`。
需要注意的是,在连续赋值语句中的延时具有硬件电路中惯性延时的特性。也就是说,**任何小于其延时的信号变化脉冲将被滤除掉,不会体现在输出端口上**。关于这部分内容会在后续详细描述。 需要注意的是,在连续赋值语句中的延时具有硬件电路中惯性延时的特性。也就是说,**任何小于其延时的信号变化脉冲将被滤除掉,不会体现在输出端口上**。
另外,`assign` 语句中的延时特性通常是被逻辑综合工具忽略的。因为综合工具要将 Verilog 语言模型综合成逻辑电路,而逻辑电路的延时是由基本的单元库和走线延时决定的。用户无法对逻辑单元指定延时,但是,用户可以在综合和实现工具中加时序约束,让工具尽量满足设计的时序要求。 另外,`assign` 语句中的延时特性通常是被逻辑综合工具忽略的。因为综合工具要将 Verilog 语言模型综合成逻辑电路,而逻辑电路的延时是由基本的单元库和走线延时决定的。用户无法对逻辑单元指定延时,但是,用户可以在综合和实现工具中加时序约束,让工具尽量满足设计的时序要求。
@@ -710,7 +710,7 @@ Verilog 作为硬件描述语言,最重要的特性就是其设计层次比较
高级编程语分为3大类: 高级编程语分为3大类:
- `if ... else` 语句; - `if ... else` 语句;
- case语句; - `case` 语句;
- 循环语句:`forever`、`repeat`、`while`、`for`。 - 循环语句:`forever`、`repeat`、`while`、`for`。
下面将逐一介绍。 下面将逐一介绍。
@@ -1405,7 +1405,7 @@ Verilog 支持不同设计层次的混描述。
# 参考文献 # 参考文献
EDA 先锋工作室. *轻松成为设计高手——Verilog HDL 实用精解.* 北京航空航天大学出版社, 2012. EDA 先锋工作室. _轻松成为设计高手——Verilog HDL 实用精解._ 北京航空航天大学出版社, 2012.
[Part 2——Verilog 语言基础]: https://josh-gao.top/posts/fd2ca242.html [Part 2——Verilog 语言基础]: https://josh-gao.top/posts/fd2ca242.html
[Part 2——Verilog 语言基础的 2.2 3 种描述方法]: https://josh-gao.top/posts/fd2ca242.html#toc2.2 [Part 2——Verilog 语言基础的 2.2 3 种描述方法]: https://josh-gao.top/posts/fd2ca242.html#toc2.2