【例说】VerilogHDL编译器指令,你见过⼏个?
Verilog HDL 编译器指令
复杂⼀点的系统在进⾏设计或者验证时,都会⽤到⼀些编译器指令,那么什么是编译器指令?
Verilog HDL编译器指令由重⾳符(')开始。在Verilog 语⾔编译时,特定的编译器指令在整个编译过程中有效(编译过程可跨越多个⽂件),直到遇到其它的不同编译程序指令。不完整的标准编译器指令如下:
下⾯分解⼀下,每个指令单独说明⼀下:
’define和’undef
1.’define指令
’define指令⽤于⽂本替换,它很像C语⾔中#define指令。它⽣成⼀个⽂本宏。该指令既可以在模块内部定义,也可以在模块之外定义。⼀旦编译了’define指令,它在整个编译过程中都有效。
如果已经定义了⼀个⽂本宏,那么在它的宏名之前加上重⾳符号(’)就可以在源程序中'引⽤该⽂本宏。
在编译器编译时,将会⾃动⽤相应的⽂本块代替字符串'macro_name。将Verilog HDL中的所有编译指令都
看作预定义的宏名,将⼀个编译指令重新定义为⼀个宏名是⾮法的。
⼀个⽂本宏定义可以带有⼀个参数。这样,就允许为每⼀个单独的应⽤定制⽂本宏。
⽂本宏定义的语法格式如下:
'define <text_macro_name> <macro_text>
其中: (1)<text_macro_name>为⽂本的宏名字,其语法格式为
text_macro_identifier[<list_of_formal_arguments>]
①text_macro_identifier为宏标识符,要求简单标识符。
②<list_of_formal_arguments>为形参列表。⼀旦定义⼀个宏名,就可以在源程序的任何地⽅使⽤它,⽽没有范围限制。
(2)<macro_text>为宏⽂本,可以是与宏名同⾏的任意指定⽂本。
①如果指定的⽂本超过⼀⾏,那么新的⼀⾏需要⽤反斜杠()作为起始。这样,反斜杠后⾯的⽂本也将作为宏⽂本的⼀部分,参与宏替换。反斜杠本⾝并不参与宏替换,编译时将忽略它。
②如果宏⽂本包含了⼀个单⾏注释语句(以“//”开始的注释语句),则该语句不属于替换⽂本,编译时不参与替换。
③宏⽂本可以空⽩。
[例] ’define指令Verilog HDL化述的例⼦1。
'define wordsize 8reg[1:'wordsize] data;
//define a nand with variable delay
'define var_nand(dly) nand #dly'var_nand(2) gl21 (q21, nl0, nil);
'var_nand(5) gl22(q22, nl0, nil);
[例] ’define指令Verilog HDL⾮法描述的例⼦2
'define first_half 'start of string$ display( ’first_half end of string');
[例] 'define 指令 Verilog HDL ⾮法描述的例⼦ 3。
'define max(a,b)((a)>(b)?(a):(b))n = 'max(p + q, r + s) ;
将要扩展为
n = ((p + q ) >(r + s))?(p + q ) :(r + s);
2.'undef指令
'undef指令⽤于取消前⾯定义的宏。如果先前并没有使⽤指令’define进⾏宏定义,那么使⽤’undef指令将会导致⼀个警告。
’undef指令的语法格式如下:
'undef text_macro_identifier
⼀个取消的宏没有值,就如同没有被定义⼀样。
'define SIZE 8'define xor_b(x,y)(x &!y)|(!x & y)
//These text macros can be used as follow:
reg ['SIZE - 1 : 0] data out;c = xor_b(a, b);'undef SIZE
’celldefine和’endcelldefine
这两个指令⽤于将模块标记为单元模块,它们表⽰包含模块定义。某些PLI使⽤单元模块⽤于这些应⽤,如计算延迟。
该命令可以出现在源代码描述中的任何地⽅。但是,推荐将其放在模块定义的外部。
[例] ’celldefine指令Verilog HDL描述的例⼦。
'celldefinemodule my_and(y, a, b);output y;input a, b;assign y = a & b;endmodule'endcelldefine
’default_nettype
该指令⽤于为隐含⽹络指定⽹络类型,也就是为那些没有被说明的连线定义⽹络类型。它只可以出现在模块声明的外部,允许多
个’default_netype指令。
如果没有出现’default_netype指令,或者如果指定了’resetall指令,则隐含的⽹络类型是wire。当default_netype设置为none时,需要明确地声明所有⽹络;如果没有明确地声明⽹络,则产⽣错误。
’default_netype指令格式为:
'default_nettype default_nettype_value
其中default_nettype_value的值可以是wire、tri、tri0、tri1、wand、triand、wor、trior、trireg、uwire和none。
'ifdef、 'else、 ’elsif、 ’endif 和’ifndef
'ifdef编译器命令
条件编译:
显⽽易见,即只有在条件满⾜的时候才对这部分代码进⾏编译,也就是对⼀部分内容指定了编译的条件:
c语言编译器ide代码编辑当满⾜条件时对⼀组语句进⾏编译,
当条件不满⾜时则对另外⼀组语句进⾏编译。
⽤途:
1、选择⼀个模板的不同代表部分。
2、选择不同的时序或结构信息。
3、对不同的EDA⼯具,选择不同的激励。(如:Verilog代码中的⼀部分可能因编译环境不同⽽不同,为避免在不同环境需要替换不同版本的Verilog 设计,条件编译就是⼀个很好的解决⽅案)
⽤法
'ifdef 宏名(标识符)程序段1...'else
程序段2...
'endif
当宏名被定义过了,就编译程序段1;反之,当宏名未被定义过,就编译程序段2;
其中,else部分可以省略。即:当宏名被定义过了,就编译程序段1;反之,不编译程序段1;
[例] ’ifdef 指令 Verilog HDL 描述的例⼦。
module and_op (a, b, c);
output a;
input b, c;
'ifdef behavioral wire a = b & c;'else
and a1 (a,b,c);
'endifendmodule
'ifndef编译器命令
额外的,还有'ifndef语句,与’ifdef功能相反:
即当宏名没被定义过,就编译程序段1;反之,当宏名未被定义过了,就编译程序段2;
'ifndef 宏名(标识符)程序段1...'else
程序段2...
'endif
[例] ’ifndef 指令 Verilog HDL 描述的例⼦。
module test;
'ifdef first_block 'ifndef second_nest
initial $ display('first_block_is_defined');
'else initial $ display('first_block and second_nest defined'); 'endif
'elsif second_block initial $ display( 'second_block defined, first_block is not”);'else
'ifndef last_result initial $ display('first_block, second_block,' ”last_result not defined.');'elsif real_last
initial $ display('first_block, second_block not defined,'
' last_result and real last defined.');
'else initial $ display('Only last result defined!'); 'endif
'endifendmodule
这⾥还有⼀个'elsif指令,简单说明⼀下。
'ifndef test_macro_identifierifndef_group_of_1ines{ 'elsif text_macro_identifier elsif_group_of_lines }
[ 'else else_group_of_lines ]'endif
①当遇到’ifndef时,测试’ifdef⽂本宏标识符,查看在Verilog HDL源⽂件描述中是否使⽤'define作为⼀个⽂本宏名字;②如果’ifndef没有定义⽂本宏标识符,则对’ifndef所包含的⾏作为描述的⼀部分进⾏编译,如果还有’else或者’dsif编译器指令,则忽略这些编译器指令和相关的⾏组;③如果定义’ifiidef⽂本宏标识符,则忽略’ifndef所包含的⾏;④如果有’elsif编译器指令,测试'elsif⽂本宏标识符,查看在Verilog HDL源⽂件描述中,是否使⽤'define作为⼀个⽂本宏名字;⑤如果’elsdef定义⽂本宏标识符,则对’elsdef所包含的⾏作为描述的⼀部分进⾏编译,如果还有’else或者’elsif编译器指令,则忽略这些编译器指令和相关的⾏组;⑥如果没有定义第⼀个'elsif⽂本宏标识符,则忽略第⼀个’elsif所包含的⾏;⑦如果有多个’elsif编译器命令,将按照它们在Verilog HDL源⽂件中的描述顺序和评估第⼀个’elsif编译器指令的⽅法,对这些指令进⾏评估;⑧如果有⼀个’else编译器命令,则将’else所包含的⾏作为描述的⼀部分进⾏编译。
’include
在编译期间,’include编译器指令⽤于嵌⼊另⼀个⽂件的内容。既可以⽤相对路径名定义⽂件,也可以⽤全路径名定义⽂件。其语法格式为: 'include 'filename'
使⽤’inchide编译器指令的优势主要体现在以下⼏⽅⾯:
(1)提供了⼀个配置管理不可分割的⼀部分;
(2)改善了VerilogHDL源⽂件描述的组织结构;
(3)便于维护Verilog HDL源⽂件描述。
[例 ]’include指令Verilog HDL描述的例⼦。
'include 'parts/count. v''include 'fileB'
'include 'fileB' //包含 fileB
'resetall
该编译器遇到’resetall指令时,会将所有的编译指令重新设置为默认值。推荐在源⽂件的开始放置’resetall.将'resetall命令放置在模块内或者UDP声明中是⾮法的。其语法格式为
'resetall
’line
对于Verilog⼯具来说,跟踪Verilog HDL源⽂件的名字和⽂件的⾏的⾏号是⾮常重要的,这些信息可以⽤于调试错误消息或者源代
码,Verilog PL1访问可以它。
然⽽,在很多情况下,Verilog源⽂件由其他⼯具进⾏了预处理。由于预处理⼯具可能在Verilog HDL源⽂件中添加了额外的⾏,或者将多个源代码⾏合并为⼀个⾏,或者并置多个源⽂件,等等,可能会丢失原始的源⽂件和⾏信息。
'line编译器命令可以⽤于指定的原始源代码的⾏号和⽂件名。如果其他过程修改了源⽂件,这允许定位原始的⽂件。当指定了新⾏的⾏号和⽂件名时,编译器就可以正确地定位原始的源⽂件位置。然⽽,这要求相应的⼯具不产⽣’line命令。
其语法格式为
'line number 'filename' level
其中,number是⼀个正整数,⽤于指定跟随⽂本⾏的新⾏⾏号,filename是⼀个字符串常数,将其看作⽂件的新名字,⽂件名可以是全路径名字或者相对路径名字;level为该参数的值,可以是0、1或者2:①当为1的时候,输⼊⼀个include⾏后的下⾯⼀⾏是第⼀⾏;②当为2的时候,退出⼀个inlcude⾏后的下⾯
⼀⾏是第⼀⾏;③当为0的时候,指⽰任何其他⾏。
[例] 'line 指令 Verilog HDL 描述的例⼦。
[例] 'line 指令 Verilog HDL 描述的例⼦。
'line3 'orig.v' 2
//该⾏是 orig.v 存在 include ⽂件后的第 3 ⾏。
’timescale
在Verilog HDL模型中,所有的时延都⽤单位时间表述。可使⽤'timescale编译器指令将时间单位与实际时间相关联,该指令⽤于定义时延的单位和时延精度。
作⽤:
timescale⽤于定义延时的单位和延时的精度,如timescale 1ns/100ps那么时间单位就是1ns,精度就是100ps。
时间单位,表⽰了仿真时测量的单位,⽐如延时1,1ns;精度则表⽰仿真器只识别的范围,⽐如精度是
100ps,那么如果你1.3ns,编译器是识别,但是如果写1.32,那么由于精度达不到那么细,所以0.02被四舍五⼊掉。
`timescale影响着全部模块,直到遇到另外的timescale。
’timescale编译器指令格式为:
’timescale time_unit/time_precision
其中,time_unit指定⽤于时间和延迟测量的单位,可选的值为1、10或100;time_precision⽤于仿真前,确定四舍五⼊延迟值。时间分辨率⼦,可选的单位为s \ms\us\ns\ps或fs。
[例] 'timescale 指令 Verilog HDL 描述的例⼦。
'timescale 10 ns / 1 nsmodule test;reg set;parameter d = 1.55;initial begin# d set = 0;# d set = 1;endendmodule
根据时间精度,参数 d 的值从 1.55 四舍五⼊到 1.6。模块的时间单位是 10ns 精度是1 ns。因此,参数 d 的延迟从 1.6 标定到 16。
’unconnected_drive和'nounconnected_drive
当⼀个模块所有未连接的端⼝出现在'unconnected_drive和’nounconnecteddrive指令之间时,将这些未连接的端⼝上拉或者下拉,⽽不是按通常的默认值处理。
指令’unconnected_drive使⽤pull1/pull0参数中的⼀个:当指定pull时,所有未连接的端⼝⾃动上拉;当指定pill0时,所有未连接的端⼝⾃动下拉。
建议成对使⽤’unconnected_drive和'nounconnected_drive指令,但不是强制要求。这些指令在模块外部成对指定。
'resetall指令包括'nounconnected_drive指令的效果。
[例]nounconnected_drive/ 'unconnected drive 指令 Verilog HDL 描述的例⼦。
'unconnected_drive pull1module my_and(y, a, b);output y;input a, b;assign y = a & b;endmodulemodule test;reg b;wire y;my_and ul(y, ,b);endmodule'nounconnected_drive
'pragma
’pragma指令是⼀个结构化的说明,它⽤于改变对Verilog HDL源⽂件的理解。由这个指令所引⼊的说明称为编译指⽰。编译指⽰不同于Verilog HDL标准所指定的结果,它为指定实现的结果。其语法格式为
’pragma pragma_name [ pragma_expression { , pragma_expression } ]
其中 ,pragma_name 为编译指⽰的名字,可以是 $ 开头的系统标识符或者⼀般标识符; pragma_expression 为编译指⽰表达式。
注:reset和resetall编译指⽰将恢复默认值和pragma_keywords所影响的状态。
'begin_keywords和’end_keyword
'begin_keywords和'end_keyword指令⽤于指定在⼀个源代码块中,基于不同版本的IEEE_Stdl364标准,确定⽤于关键字的保留字。该对指令只指定那些作为保留关键字的标识符。只能在设计元素(模块、原语和配置)外指定该关键字,并且需要成对使⽤。其语法格式为:
'begin_keywords 'version_specifier' ...'end_keyword
其中,version_specifier为可选的参数,包括1364-1995、1364-2001、1364-2001-noconfig和1364-2005。
[例] ’begin_keywords 和 'end_keyword 指令 Verilog HDL 描述的例⼦。
'begin_keywords '1364- 2001' //使⽤ IEEE Std 1364- 2001 Verilog 关键字'module m2(...);
reg[63:0] logic; //logic 不是 1364 - 2001 的关键字
...
endmodule
'end_keywords
(补充⼀)Verilog编译器指⽰语句
设计者在写设计代码时,有时可能针对仿真写⼀些语句,这些语句可能是不为DC所接受,也不希望DC接受;设计者如果不对这些语句进⾏特殊说明,DC读⼊设计代码时就会产⽣语法错误。另⼀种情况是,设计者在写设计代码,有些设计代码是为专有的对象写的(如公司内部),这些专有的设计代码可能不希望被综合。Synopsys提供了引导语句,设计者可以使⽤这些引导语句控制DC综合的对象
可以利⽤HDL描述中的⼀些特定的注释语句来控制综合⼯具的⼯作,从⽽弥补仿真环境和综合环境之间的差异,这些注释语句称为编译器指⽰语句。
translate_off/ translate_on
这组语句⽤来指⽰DC停⽌翻译 “//synopsys.。.translate_off”之后的Verilog描述,直⾄出现 “//synopsys translate_on”。当Verilog代码钟含有供仿真⽤的不可综合语句时,这项功能能使代码⽅便地在仿真⼯具与综合⼯具之间移植。
例1(translate_off/ translate_on指⽰语句的使⽤):
//synopsys translate_off
//synopsys translate_on
parallel_case/ full_case
DC可能使⽤带优先级的结构来综合Verilog的case语句,为避免这种情况,可以使⽤“//synopsys.。.parallel_case”指⽰DC将case语句综合为并⾏的多路选择器结构。
(parallel_case指⽰语句的使⽤):
always @ (state)
case (state) //synopsys parallel_case
2’b00:new_state = 2’b01;
2’b01:new_state = 2’b10;
2’b10:new_state = 2’b00;
default:new_state = 2’b00;
endcase
另外,Verilog允许case语句不覆盖所有可能情况,当这样的代码由DC综合时将产⽣锁存器。为避免这种情况,可以使⽤“//synopsys
full_case”指⽰DC所有可能已完全覆盖。
例2 (full_case指⽰语句的使⽤):
always @ (sel or a1 or a2)
case (sel) //synopsys full_case
2’b00:z = a1;
2’b01:z = a2;
2’b10:z = a1 & a2;
endcase
(补充⼆)Verilog PL1是什么?
上⾯有提到过PLI接⼝,这⾥简单介绍下,因为⽤的⽐较少,所以就⼀笔带过。
编程语⾔接⼝(Program Language Interface,PLI)提供了通过C语⾔函数对Verilog数据结构进⾏存储和读取操作的⽅法。
PLI接⼝主要提供以下三种功能。
(1)PLI接⼝允许⽤户编写⾃定义的系统任务和系统函数。⽤户写出相应的PLI程序并连接到仿真器后,就可以在⾃⼰写的VerilogHDL程序中使⽤这些系统任务和系统函数。⼀旦在仿真过程中调⽤这些任务或者函数,仿真器就会到对应的⽤户所编写的PLI程序并执⾏,从⽽实现仿真器的定制。
(2)这个接⼝还允许⽤户在⾃⼰的PLI程序中与仿真器中例化的VerilogHDL硬件进⾏交互,如读⼀个线⽹络的值、向⼀排寄存器写值以及设置⼀个单元的延迟,等等。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论