文章目录
前言
- ˋ 符号说明一个编译指令
- 这些编译指令使仿真编译器进行一些特殊的操作
- 编译指令从出现时开始有效,直到被覆盖或使其失效。因此编译指令是全局的
- ˋresetall 复位所有的编译指令为缺省值,应该在其它编译指令之前使用
- 尽管编译指令是 Verilog 语言的一部分,但其作用取决于编译器,因此不同的仿真器中其作用可能不同。
下列编译指l令是 Verilog IEEE 标准中的:
- 库单元分界
ˋcelldefine
ˋendcelldefine - 定义文本宏和基于文本宏的转换
ˋdefine
ˋundef
ˋifdef
ˋelse
ˋelsif
ˋifndef
ˋendif - 复合编译指令
ˋdefault_nettype
ˋinclude
ˋunconnected_drive
ˋnounconnected_drive
ˋresetall
ˋtimescale
一、ˋcelldefine 和 ˋendcelldefine
这两个指令用于将模块标记为库单元。
建立 Verilog 模型库,需要:
- 每个元件(或单元)用一个 module 描述
- 将相关的 module 放在同一个文件或同一个目录中(当把 module 放到同一个目录时,文件名应与 module 名相同。文件名的扩展名是可选的)
可以用两种抽象级描述库单元
- 结构级
– 用 Verilog 基本单元或 UDP
– 用于描述组合逻辑或简单的时序逻辑 - 行为级
– 用过程块或赋值语句
– 用于描述大的或复杂的元件,如 RAM 或 ROM
库单元的特点:
- 每个库单元的描述在编译指令 ˋcelldefine 和 ˋendcelldefine 之间
- 每个库单元的描述有两部分:
– 功能描述
– 时序描述
`celldefine
`timescale 1ns/100ps //在模块定义之前插入 `timescale 定义单元所使用的时间单位和精度
module full_adder (cout, sum, a_in, b_in, c_in);
input a_in, b_in, c_in;
output cout, sum;
// 功能描述
...
// 时序描述
...
endmodule
`endcelldefine
二、ˋdefine 和 ˋundef
编译指令 ˋdefine 提供了一种简单的文本替换的功能
ˋdefine <macro_name> <macro_text>
在编译时 <macro_text> 替换 <macro_name>。可提高描述的可读性。
`define not_delay #1 // 定义 not_delay
`define and_delay #2
`define or_delay #1
module MUX2_1 (out, a, b, sel);
output out;
input a, b, sel;
not `not_delay not1( sel_, sel); // 使用 not_delay
and `and_delay and1( a1, a, sel_);
and `and_delay and2( b1, b, sel);
or `or_delay or1( out, a1, b1);
endmodule
ˋdefine 相关要点:
- ˋdefine 可以写在模块外和模块内,有效范围为定义之后到原文件结束。通常将其定义在 module 外, 作为程序的一部分,在此程序内都有效。
- 在引用已定义的宏名时,必须在宏名的前面加上符号ˋ,表示该名字是一个经过宏定义的名字。
- 宏定义是用宏名代替字符串,也就是做简单的置换,不做语法检查。只有在编译已经被宏展开后的源程序时才报错。
- 宏定义不是 Verilog HDL 语句,不必在行末加分号,加分号则分号也被当成宏内容字符串进行替换。
- 宏定义可以嵌套,定义一个新的宏定义时可以引用之前定义过的宏定义进行嵌套。
- 宏名和宏内容必须在同一行进行声明,宏内容中如果有注释行,注释行不会被替换。
- 所有编译器指令均被视为预定义的宏名称; 将编译器指令重新定义为宏名称是非法的。
解除定义的宏,使用 ˋundef <macro_name>
使用编译指令 ˋdefine,可以
- 提高描述的可读性
- 定义全局设计参数,如延时和矢量的位数。这些参数可以定义在同一位置。这样,当要修改设计配置时,只需要在一个地方修改。
- 定义 Verilog 命令的简写形式
ˋdefine vectors_ file “/usr1/chrisz/library/vectors”
ˋdefine results_ file “/ usr1/chrisz/library/results”
可以将ˋdefine 放在一个文件中,与其它文件一起编译。
三、ˋifdef,ˋelse,ˋelsif,ˋifndef 和 ˋendif
这些属于条件编译指令。例如下面的例子中,如果定义了 A,则使用第一种参数说明;如果没有定义 A、定义了 B,则使用第二种参数说明;如果两个都没有定义,则使用第三种参数说明。
`ifdef A
parameter DATA_DW = 8;
`elsif B
parameter DATA_DW = 64;
`else
parameter DATA_DW = 32;
`endif
ˋelsif,ˋelse 编译指令对于 ˋifdef 指令是可选的,即可以只有 ˋifdef 和 ˋendif 组成一次条件编译指令块。
当然,也可用 ˋifndef 来设置条件编译,表示如果没有相关的宏定义,则执行相关语句。
下面例子中,如果定义了 A,则使用第二种参数说明。如果没有定义 A,则使用第一种参数说明。
`ifndef A
parameter DATA_DW = 32;
`else
parameter DATA_DW = 64;
`endif
四、ˋdefault_nettype
Verilog 主要有三类(class)数据类型:
- net (线网):表示器件之间的物理连接
- register (寄存器):表示抽象存储元件
- parameters(参数):运行时的常数(run-time constants)
net 需要被持续的驱动,驱动它的可以是门和模块。
当 net 驱动器的值发生变化时, Verilog 自动的将新值传送到 net 上。在例子中,线网 out 由 or 门驱动。当 or 门的输入信号置位时将传输到线网 net 上。
有多种 net 类型用于设计(design-specific)建模和工艺(technology-specific)建模。
- wire 类型是最常用的类型,只有连接功能。
- wire 和 tri 类型有相同的功能。用户可根据需要将线网定义为 wire 或 tri 以提高可读性。例如,可以用 tri 类型表示一个 net 有多个驱动源。或者将一个 net 声明为 tri 以指示这个 net 可以是高阻态 Z(hign-impedance)。可推广至 wand 和 triand、wor 和 trior。
- wand、wor 有线逻辑功能;与 wire 的区别见下表。
- trireg 类型很像 wire 类型,但 trireg 类型在没有驱动时保持以前的值。这个值的强度随时间减弱。
net 类在发生逻辑冲突时的决断:
没有声明的 net 的缺省类型为 1 位(标量)wire 类型。但这个
缺省类型可由下面的编译指令改变:
ˋdefault_nettype
nettype 不能是 supply1 和 supply0。
五、ˋinclude
编译指令 ˋinclude 在当前内容中插入一个文件
格式:ˋinclude “<file_name>”
如:
ˋinclude “global.v”
ˋinclude “parts/count. v”
ˋinclude "…/…/library/mux. v”
可以是相对路径或绝对路径。
- ˋinclude 可用于:
– ˋinclude 保存在文件中的全局的或经常用到的一些定义,如文本宏。
– 在模块内部 ˋinclude 一些任务(tasks),提高代码的可维护性。
六、ˋunconnected_drive 和 ˋnounconnected_drive
在模块实例化中,出现在这两个编译指令间的任何未连接的输入端口,为正偏电路状态或者为反偏电路状态。
`unconnected_drive pull1
...
// 在这两个程序指令间的所有未连接的输入端口为正偏电路状态(连接到高电平)
`nounconnected_drive
`unconnected_drive pull0
...
// 在这两个程序指令间的所有未连接的输入端口为反偏电路状态(连接到低电平)
`nounconnected_drive
七、ˋresetall
该编译指令将所有的编译指令重新设置为缺省值。
- ˋresetall 可以使得缺省连线类型为线网类型。
- 当 ˋresetall 加到模块最后时,可以将当前的 ˋtimescale 取消防止进一步传递,只保证当前的 ˋtimescale 在局部有效,避免 ˋtimescale 的错误继承。
- 当使用编译指令 ˋresetall 时,IEEE 规范没有说明如何处理文本宏。 Cadence Verilog 仿真器在遇到 ˋresetall 时,文本宏定义不变。要清除文本宏定义,使用 ˋundef <macro_name>。
八、ˋtimescale
ˋtimescale 说明时间单位及精度
格式:ˋtimescale <time_unit> / <time_precision>
如:
ˋtimescale 1ns / 100ps
time_unit:延时或时间的测量单位
time_precision:延时或时间的精度,延时值超出精度要先舍入后使用
- ˋtimescale 必须在模块之前出现
- time_precision 不能大于 time_unit
- time_precision 和 time_unit 的表示方法:integer unit_string
– integer:可以是 1, 10, 100
– unit_string:可以是 s(second), ms(millisecond), us(microsecond),ns(nanosecond), ps(picosecond), fs(femtosecond)
– 以上 integer 和 unit_string 可任意组合 - precision 的时间单位应尽量与设计的实际精度相同。
– precision 是仿真器的仿真时间步。
– 若 time_unit 与 precision_unit 差别很大将严重影响仿真速度。
– 如说明一个 ˋtimescale 1s / 1ps,则仿真器在 1 秒内要扫描其事件序列 1012 次;而 ˋtimescale 1s / 1ms 则只需扫描 103 次。 - 如果没有 ˋtimescale 说明将使用缺省值,一般是 ns。
- 在编译过程中,ˋtimescale 指令会影响后面所有模块中的时延值,直至遇到另一个 ˋtimescale 指令或 ˋresetall 指令。
– 由于在 Verilog 中没有默认的 ˋtimescale,如果没有指定 ˋtimescale,Verilog 模块就有会继承前面编译模块的 ˋtimescale 参数。有可能导致设计出错。
– 所有 ˋtimescale 中的最小值决定仿真时的最小时间单位。这是因为仿真器必须对整个设计进行精确仿真。
在下面的例子中,仿真时间单位(STU)为 100fs。
`timescale 1ns / 10ps
module1 (...);
not #1.23 (...) // 1.23ns or 12300 STUs
...
endmodule
`timescale 100ns / 1ns
module2 (...);
not #1.23 (...) // 123ns or 1230000 STUs
...
endmodule
`timescale 1ps / 100fs
module3 (...);
not #1.23 (....) // 1.23ps or 12 STUs (rounded off)
...
endmodule