Verilog基础
丽桑卓出装-工作执行力
Verilog基础
一基本要素
(1)Verilog HDL与VHDL
1.它于1995年成为IEEE标准,即standard
1364-1995。VHDL于1987年成为IEEE标准。
2.类C语言,不允许自定义数据类型(VHDL可以)。
3.可描述开关级电路
模型,但信号初值不确定,必须由程序初始化;VHDL系统数据定义后
没有赋值则默认为0,对系统级
支持能力要强一些。
(2)IC设计流程:
系统结构设计与仿真——
>HDL设计——>TestBench功能模拟测试、逻辑仿真——>综合成
逻辑门(工艺库、约束文
件)——>初步时序分析(静态、电压、温度)——>自动布线布
局——>后端报告(布局布线后增加的
电阻、电容)——>动态(布局后)时序仿真,任何的建
立例外都必须通过优化产生该例外的路径,以减
小延迟;任何保持例外都必须通过在产生例
外的路径上增加缓存,来增加延迟——>逻辑验证——>投片
生产。
(3)标识符与关键字命名
1.标识符首字不能为数字或$$,可以为字母和下划线,
2.命名长度不能超过1024,
3.区分大小写(与VHDL不同);
4.系统任务和系统函数前必须在标识符前加上$$。
5.转义标识符
开头,以空格、制表符(tab键)或换行符结尾,可显示打印ASCII字符。
(4)系统任务和系统函数
y(信息输出到标准输出设备,带行结束符)和wri
te(输出信息不带行结束符)。用
于显示输出的特殊字符:
n 换行
t 制表符
字符
字符
ddd 值为十六进制字符
%% 字符%
格式定义:
%h或%H: 十六进制
%d或%D: 十进制
%o或%O:
八进制
%b或%B: 二进制
%c或%C:
ASCII字符
%v或%V: 线网信号长度
%m或%M: 层次名
%s或%S: 字符串
%t或%T: 当前时间格式
缺省如$$displayb: 显示二进制数,
r 监控和显示指定任务的参数值,
显示数据,保证数据只在所有赋
值语句执行完毕时才被显示;(而$$display()任务执
行通常是确定的)。
4.文件输入输出
a.文件打开和关闭:系统函数$$fopen()和$$fclose(),
b.输
出值到文件:$$fdisplay,$$fwrite,$$fstrobe,$$fmonitor,这些任务的第一
个参数都是文件指针,
其余参数为带有从参数表的格式定义序列。
c.从文件中读
出数据并载入存储器:$$readmemb,$$readmenh用于指定文件中读取并载入数据
到指定
的存储器。可在模拟时间的任何时刻执行,读取的文件只能包含如下内容:
空格、换行符、制表符(tab键)、换页;注释;二进制和十六进制;
5.模拟时间访问当前模拟时间,
a.$$time:返回64位的整型模拟时间值,由`timescale激活;
b.$$stime:返回32位无负号整型时间值,在`timescale中指定单位,
c.$$realtime:返回一个实数,在`timescale中指定单位;
6.模拟控制
a.$$finish[(n)];使模拟器窗口关闭并控制返回主机操作系统;
b.$$stop[(n)];将模拟进程挂起;
7.随机函数
$$random[(seed)];
产生随机数,每次调用时根据种子变量(seed
)的取值返回一个新的32位有符号随机
数。种子变量必须是寄存器型、整型或时间寄存器型,种子变量
来控制函数返回值,改变量
的值应该在调用$$random系统函数之前就已定义好。其他产生随机数函
数:
$$dist_uniform(seed,start,end);
$$dist_normal(seed,mean,standard_deviation,upper);
$$dist_exponential(seed,mean);
$$dist_poisson(seed,mean);
$$dist_chi_square(seed,degree_of_freedom);
$$dist_t(seed,degree_of_freedom);
$$dist_erlang(seed,k_stage,mean);
(5)编译指令
1.`difine,`undef,产生取消文本替换的宏;
2.`ifdef,`else,`endif,条件编译;
3.`defaul
t_nettype,为隐式线网指定线网类型,在模块外使用,影响其后的所有模块;线网
类型的关键
字有:
wire,tri,tri0,wand,triand,tri1,wor,trior,trireg;
4.`include,包含源文件,可以嵌套,如果文件1包含文件2,文件2包含文件3
,则在文件
1中用2条该指令包含且文件3出现在前;
5.`resetall,重设为缺省值;
6.`timescale,说明时间
单位和精度,$$printtimescale显示模块的时间单位和精度;
7.`unc
onnected_drive,`nounconnected_drive,出现在这两个指令之间的任何未
连接的输入端口
呈现为正偏电路状态(连接到高电平)或反偏电路状态(连接到低电平)。
8.`celldefine,`endcelldefine,这两个指令之间为单元模块。
(6)空白符和注释
空格、制表符、换行符、走纸符没有特殊意义;
注释形式多行或单行用,
(7)数值和字符串
1.
4种基本值:0,1,x未知,z高阻;x和z不区分大小写;
2. 3种基本常量:整
型,实型,字符串型;八进制(o或O),二进制(b或B),十进
制(d或D),十六进制(h或H)
;科学计数法,2_3.5e2值为2350.0忽略下划线;字符
串在双引号内,不能分多行写;
(8)线网类型
和tri:连线和三态线网,可描述多个驱动源驱动同一线网类型,具体值由下表决定:
wire 0 1 x z
0 0 x
x 0
1 x 1 x 1
x
x x x x
z 0 1 x z
和trior:线或线网;
和triand:线与网;
:三态寄存器,用于存储数值,并可用于电容节电建模;
0和tri1线网:用于线逻辑的建模,若无驱动源驱动,则tri0的值为0(tri1的值为1);
0和supply1:前对地建模,电平为0;后者对电源建模,即高电平1;
(9)寄存器类型
:可以取任意长度,值通常被解释为无符号数;
<
br>r:整型值,最多容纳32位;可以存储有符号数,且算术操作符提供2的补码运算结
果;不能位
访问,一种截取位的办法是将整数赋值给一般的reg型变量,然后从中选取相应
的位,综从右向左截取
(获得最低位),多余的(高位)被截断;
:存储和处理时间,只存储无符号值,默认为64位值;
(10)门类型
:一个标量输出多个标量输入,门共有:
and or
xor
nand nor xnor
:一个标量输入和多个标量输出;
(11)操作符
优先级:由高到低,
!(逻辑非),
&,~&,|,~|,^,~^,规约操作符在单一操作数的所有位上进行操作,并产生1位结果;
+,-,正负;
*,(只取整,余数丢弃),%(求余数,两侧均为整型);
+,-,加减;
<<,>>,移位操作,空位补0,
>,<,>=,<=,
==,!=,===(等于),!==(不等于);
&,~&,~,^(按位异或),^~(同或),位运算操作,右端对齐;
|,~|,
&&(逻辑与),
||,逻辑操作,
?:,条件操作,
{},连接操作,可把多个信号的某些位连接起来进行位运算操作表示一个新信号,还可
以嵌套;
=,<=,赋值,
复制操作符,{重复数字{重复内容}};
二行为建模与基本的行为建模语句
1.过程语句
并发执
行,时序条件或事件触发。每个模块中可以含任意个initial和always语句,块
内部可顺序
执行,块间的语句可以交叉执行。较适合的做法是在always语句中描述硬件行
为,在年语句中模块
初始化。
(a)initial:在仿真开始时,且该块仅执行一次,常用于测试和虚拟模
块中,多个initial语
句之间并行;可以是下列语句之一:
assign 阻塞或非阻塞过程赋值语句
continous
连续赋值语句
conditioal 条件语句
case
case语句
loop 循环
wait 等待
disable 终止
sequential 顺序执行块
parallel 并行执行块
task 任务使能语句
(b)always [
@(timing_control)]:循环执行,触发条件由时序控制决定,可以电平触发也可
边沿
触发(negedge,posedge),还可以多个信号用or连接,满足条件才执行,否则阻塞并
等待再次满足条件,所以输入的变化会影响输出;可用语句与initial类似;缺省条件则产生
一个
仿真死锁。
边沿触发常用于描述时序行为,如有限状态机等;电平触发常用来描述组合逻辑行为。
2.条件语句
(a)if() else if() else;
(b)条件操作符(?:)二选一;
endcase语句
多分支枚举选择,表达式长度要统一。派生的casez和casex语句,在casex句中值x
(未
知)和z(高阻)都被认为是无关位,if句中表达式产生的x或z值将出错;在casez
句中值z被
认为是无关值。如casez(mask)4`b1???:Dbus[4]=0;表示第4位是1忽略其他位。
4.循环语句
(a)forever:连续执行,跳出语句disable可与过程语句同使用;
(b)repeat():执行固定次数,计数表达式值X或z不定是,按0处理;
(c)while():执行过程赋值语句直到指定的条件为假,如果表达式开始就假,则不执行;
(d)for:
(e)循环的异常退出:disable,可退出任何
循环,能终止任何begin_end块的执行,块名可
放在begin关键字后冒号后。
5.事件控制
在verilog2001新规范中@(a,b,c)和@(a or b or c)等价,
(a)边沿触发事件 @event :posedge和negedge表示上升沿转换的形式有:
0->x,0->z,0->1,x->1,z->1;
下降沿转换形式有:
1->z,1->x,1->0,x->0,z->0;
(b)电平触发事件 wait()
6.持续赋值
赋值给预先定义好的网线,在模拟期间只要且只有等式右边有变化,就赋值给左边,且连
续、自动完成;若有指定赋值延迟,则在右边变化后过一定延迟时间再赋值给左边;用于数
据流行为建
模,常用在组合逻辑设计。
assign a=b;
7.过程赋值语句
用来更新寄存器型、整型、时间型和存储器型变量;与持续赋值的区别:
一,在过程控
制流下控制更新寄存器变量;assign驱动线网,且在输入操作值变化时求
解新值并更新变量;
二,在过程块内部;assign句在过程块外步;
三,通常用在initial和always块中,只能对寄存器型变量赋值;
·通常在always块中用阻塞性赋值来产生组合逻辑;
·通常在always块中用非阻塞性赋值来产生时序逻辑;
(a)verilogHDL的层次化事件模型:IEEE标准中四个独立层次化事件队列:
动态事件队列
停止运行的事件队列()顺序可变:
阻塞赋值,计算非阻塞赋值右边的表达式,持续赋值,执行$$display命令,
计算原语的
输入和输出变化;
非阻塞事件队列:
#0延迟阻塞赋值;
监控事件队列:
更新非阻塞赋值语句左边变量的值;
其他指定的PLI命令队列:
执行$$monitor命令,$$strobe命令;
所有事件可以加入到任何一个事件队列中,但只能从活跃事件队列中移出。
8条可综合风格的VerilogHDL编码规则(尽量避免条件竞争):
·时序逻辑建模使用非阻塞赋值;
·锁存器建模使用非阻塞赋值;
·在always块中组合逻辑建模使用阻塞赋值;
·在同一个always块中对时序逻辑和组合逻辑同时建模使用非阻塞赋值;
·不要在同一个always块中混和使用阻塞和非阻塞赋值;
·不要在多个always块中对同一个变量赋值;
·使用$$strobe命令显示对非阻塞语句进行的赋值;
·不要使用零延迟赋值语句。
(b)阻塞性过程赋值
必须在顺序块中后续语句执行前执行完毕,但不能阻止并行块中后续语句执行;如:
reg y1,y2;
y1=0;y2=1;
(c)非阻塞性过程赋值
在时钟拍开始时刻计算右边表达式的
值,在时钟拍结束时刻赋值给左边表达式,即在计
算结果和更新变量期间可以计算其他语句表达式的值并
更新,就是非阻塞赋值语句不阻塞其
他语句的执行。
那么各条非阻塞语句各自独立,并行执行,不会阻塞其他语句执行。为非阻塞赋值
符号,例:reg
x1,x2;x1<=9;x2=5;
非阻塞赋值语句只能对寄存器操作,因此只能在
过程块(initial和always)内部实现。
如果时序逻辑和组合逻辑同时在一个always
块中出现,常用非阻塞赋值,把这个always块
当作时序逻辑来处理。
单独阻塞赋值表示的组合逻辑和单独非阻塞赋值表示的时序逻辑混合,例如:
module ex1(q,a,b,clk,rst_n);
output q;
input clk,rst_n,a,b;
reg
q,y;
always @(a or b)
y=a^b;
always @(posedge clk or negedge
rst_n)
if(!rst_n)
q<=1`b0;
else
q<=y;
endmodule
建议在所有的时序逻辑编码中使用非阻塞赋值。
三
结构化建模
1.三种示例化描述
结构级描述是在门级或更高级的层次上描述数字系统,有三种示例化的语句来描述:
·原语(primitive)示例,即逻辑门;
·用户自定义基元(UDP)示例,逻辑门的一种扩展;
·模块(module)示例。
VerilogHDL定义了14种原语,分4大类:多输入门、多输出门、三态门和pull门。
不能在一个module内部定义UDP,要在其外面,但UDP只能有一个输出,且输入中
不能出现总线结构。
模块比UDP更灵活,可支持任意复杂和任意端口数目,所有实
际结构化描述中常用模
块化的结构级描述。
2.模块
(1)
三种端口:input、output、inout;缺省的端口型默认为wire型,类型声明的长度必须与端口声明的长度一致。定义与例化一致。
(2)使用参数定义语句,使模块定义内含参数,
(3)示例化说明,使模块定义内含参数,
(4)实例设计,分行为级、数据
流、门级和开关级四种设计;示例化是建立在模块定义基
础上,一次模拟中至少有两个模块,设计模块和
测试模块;测试模块一般是顶层模块,并且
一般用行为级描述。循环计数器顶层:
module carry_counter4(q,clk,reset);
output[3:0] q;
input clk,reset;
4
instances of the module T_FF are created
T_FF
tff0(q[0],clk,reset);
T_FF
tff1(q[1],q[0],reset);
T_FF
tff2(q[2],q[1],reset);
T_FF
tff3(q[3],q[2],reset);
endmodule
用到的T型触发器:
module T_FF(q,clk,reset);
output q;
input clk,reset;
wire d;
D_FF
dff0(q,d,clk,reset);
not n1(d,q); 非门
endmodule
用到的带同步复位的D触发器:
module
D_FF(q,d,clk,reset);
output q;
input
d,clk,reset;
always @(posedge reset or negedge
clk);
if (reset)
q<=1'b0;
else
q<=d;
endmodule
测试模块:
module
stimulus;
reg clk,reset;
wire[3:0] q;
计数器例化
carry_counter4 r1(q,clk,reset);
生成时钟
initial
clk=1'b0;
always
#5 clk=~clk;主频100Hz?
输入激励控制信号
0ns--
15ns复位
initial
begin
reset=1'b1;
#15 reset=1'b0;
#180 reset=1'b1;
#10
reset=1'b0;
#20 $$finish;模拟结束
end
监视输出
initial
$$monitor($$time,
endmodule
四门级与开关级建模
行为级、寄存器传输级、门级、开关级建模针对系统的不同层次。Verilog
HDL提供了
18个门级和开关级的基本基元,设计使用时只要例化并用线网连接起来即可。
门级基元 开关级基元
多输入门
多输出门 三态门 MOS开关 双向开关
and buf
bufif0 nmos tran
nand not
bufif1 pmos tranif0
or
notif0 cmos tranif1
nor
notif1 rnmos rtran
xor
rpmos rtranif0
xnor
rcmos rtanif1
1.三类门级基元12种
多输出门buf和not门,在加上控制信号后成为三态门,
2.开关级基元14种
是实际的MOS关的抽象表示,分电阻型(前缀r表示)和非电阻型;
(1)MOS开关
·nmos开关:控制信号高,开关导通,否则关闭;
·pmos开关:控制信号低,开关导通,否则关闭;
·cmos开关
:模拟了nmos和pmos开关的组合,一般ncontrol和pcontrol是互补信号:coms
实例名(out,data,ncontrol,pcontrol);
(2)双
向开关:MOS开关只提供了单向驱动能力,双向开关的每个脚都声明为inout类型,
可做输入驱动
或输出被驱动,即可以互相驱动且随时保持一致。
无条件双向开关tran和有条件双向开
关tranif0(只有当conrol为0时两端互相驱动)、tranfi1
(当control为
1时两端互相驱动):
tranifx
实例名(inout1,inout2,control);
3.
门级建模
实际电路中逻辑门都有一定延迟,提供3种延迟:
·上升延迟(rise delay):门的输出态从(0、x、z)到1的所需时间;
·下降延迟(fall delay):门的输出态从(1、x、z)到0的所需时间;
·关断延迟(turnoff delay):三态门的输出从(0、1、x)到高阻态z所需时间。
门级建模:穷举输入输出->卡诺图->布尔函数,布尔函数的自变量就是逻辑门的输
入。
四
位全加器例:一位全加器布尔函数为sum=(a^b^cin);cout=ab+cin(a^b);门级建
模:
module fulladd(sum,c_out,a,b,c_in);
output sum,c_out;
input a,b,c_in;
internal nets
wire s1,c1,c2;
instantiate logic gate primitive
xor(s1,a,b);
and(c1,a,b);
xor(sum,s1,c_in);
and(c2,s1,c_in);
xor(c_out,c1,c2);
endmodule
四位并行全加器:
module fulladd4(sum,c_out,a,b,c_in);
output[3:0] sum;
output c_out;
input[3:0] a,b;
input c_in;
wire
c1,c2,c3;
fulladd
fa0(sum[0],c1,a[0],b[0],c_in);
fulladd
fa1(sum[1],c2,a[1],b[1],c1);
fulladd
fa0(sum[2],c3,a[2],b[2],c2);
fulladd
fa0(sum[3],c_out,a[3],b[3],c3);
endmodule
4.开关级建模
表示开关导通与关断,还表示连接开关的线网上存储电荷的容量,
即线网的强度,声明开关
示例连接时在声明说明后注明等级即可;定义的8种强度等级:
强度名称 强度等级 声明说明 打印缩写
Supply drive 7 Supply
Su
Strong drive 6 Strong St
Pull drive 5 Pull Pu
Large capacitor 4 Large La
Weak drive 3 Weak We
Medium capacitor 2 Medium Me
Small capacitor 1 Small Sm
High impedance 0 Highz Hi
使用%v格式可打印出来。为了模拟实际电路中晶体管开关自身带有电阻,就用电阻型开关<
br>表示(名字中带有r的开关),但驱动强度相应降低。
通过电阻型开关后强度降低幅度表
输入强度 输出强度
Supply Pull
Strong Pull
Pull Weak
Large Medium
Weak
Medium
Medium Small
Small
Small
Highz Highz
nmos与pmos开关实现互补型MOS电路nor门例:
module
my_nor(out,a,b);
output out;
input a,b;
wire c;
set up power and ground lines
supply1 pwr;pwr is connected to Vdd(power
supply)
supply0 gnd;gns is connected to
Vss(ground)
pmos (c,pwr,a);
pmos
(out,c,b);
nmos (out,gnd,a);
nmos
(out,gnd,b);
endmodule
五用户自定义基元UDP
通过它来实现门级基元的扩展,可模拟2种行为:
·组合行为,由UDP的组合基元来模拟;
·时序行为,由UDP的时序基元来模拟; 一个UDP可以有多个输入,但只能有一个标量输出,输出可有3种状态:0、1、x,不支持
高阻
态z,但输入的z态往往被当成x态。
1.定义
UDP的定义与模块无关,与模块属同一层次。
规则:
·只允许有一个输出端口的声明,且必须定义在输入端口的定义之前;
·不准有inout端口,不能定义成向量的形式;
·在时序UDP中,输出端口必须定义成
寄存器型,而在组合UDP中输出端口却不能定义成
寄存器型;
·逻辑实现主体全部在状态表
格table中,每一行所对应的输入激励的顺序都与前面输入端口
定义的次序一样,且与端口的实际定
义内容无关。在table中每个输入输出端口都有一个域,
输入域和输出域之间用冒号隔开,每一行定
义了输入信号所产生的特定组合输出。在时序
UDP中,还在输入域和输出域之间加入另一个域,指明U
DP目前的状态,可认为是目前
UDP的实际输出。没有列出的输入组合所对应的输出都为x。
格式:
primitive 名(接口信号表);
output;
端口声明;
input;
table 状态表格描述;
endtable
endprimitive
UDP状态表格
符号 解释 注释
0 逻辑0
1
逻辑1
x 未知逻辑
? 逻辑0、1或x 不能用于输出
b 逻辑0或1 不能用于输出
- 不变化
只用于时序基元
(vw) 从v到w 可以是0、1、x或?
*
同(??) 输入的任何变化
r 同(01)
输入上升沿
f 同(10) 输入下降沿
p
同(01)、(0x)、(x1) 含x的上升沿
n 同(10)、(1x)、(x0)
含x的下降沿
2.组合UDP
例,定义一个组合UDP并例化,
primitive mult(mux,control,data1,data2);
output mux;
input control,data1,data2;
control data1 data2:mux
0 1 0:1;
0 1
1:1;
0 1 x:1;
0 0 ?:0; ?表示0、1、x三种情况,可简化描述表
1 ? 1:1;
1 ? 0:0;
x 0 0:0;
x 1 1:1;
endtable
endprimitive
该多路选择器例化如下,
module ex1(in1,in2,in3,out1);
input in1,in2,in3;
output out1;
wire
out1;
mult mult1(out1,in1,in2,in3);
endmodule
3.时序UDP
将有一个存储元素来存储当前状态。分电平和边沿敏感2种。
(1)电平敏感的时序UDP:
比组合型多了一个寄存器,主要用来保存当前的状态,也可以
当成是当前的输出。当前的输入和状态确定
下一个输出,例:
primitive udp_latch(q1,data,clk);
output q1;
input data,clk;
reg q1;
initial
q1=0; 初始化输出信号为0
table
data
clk : q1(current) q1(next state)
0 0 : ? : -;
0 1 : ? : 0;
1 0 : ? : -; 其中?表示并不关心当前状态
1 1 : ? : 1; 它可以是0、1或x
endtable
endprimitive
(2)边沿敏感的时序UDP:某输入的跳变触发输出
的改变,表格中每一行只能有一个输入
的跳变,D触发器例如:
primitive
d_edge(q1,data,clk);
output q1;
input
data,clk;
reg q1;
initial
q1=0;
table
data clk : q1(current) q1(next)
0 (01) : ? : 0;选通,上升沿
1 (01) : ? :
1;
no change in output values
0 (0x) : ? :
-;不选通,没有上升沿
1 (0x) : ? : -;
no change for
negedge
? (?0) : ? : -;不选通,可能是下降沿
no
change for change in data
(??) ? : ? :
-;输入的变化不影响输出
endtable
endprimitive
例2,T触发器,
primitive T_FF(q1,clk,clear);
output q1;
input clk,clear;
reg q1;
table
clk clear : q1(current) q1(next)
? 1 : ? : 0;
? (10) : ? : -;忽略clear的下降沿
(10) 0 : 1 : 0;下降沿触发翻转
(10) 0 : 0 : 1;
(0?) 0 : ? : -;忽略时钟的上升沿
endtable
endprimitive
构成4位循环计数器:
module
counter4(Q,clk,clear);
IO ports
output
[3:0] Q;
input clk,clear;
T_FF
tff0(Q[0],clk,clear);
T_FF
tff1(Q[1],Q[0],clear);
T_FF
tff0(Q[2],Q[1],clear);
T_FF
tff0(Q[3],Q[2],clear);
endmodule
(3)混
合时序UDP:允许同时定义2中表,当输入变化时,优先处理边沿触发事件,再处
理电平事件;若某激
励同时触发2种事件则输出结果以电平事件为准(可理解为后修改的结
果)。
JK触发器描述的混合时序UDP:
primitive
jk_edge(q,clk,j,k,preset,clear);
output q;
input clk,j,k,preset,clear;
reg q;
table
clk j k preset clear : q(state)
q(output)
? ? ? 0 1 : ? : 1;preset
? ? ? *
1 : 1 : 1;
? ? ? 1 0 : ? : 0;clear
? ? ? 1
* : 0 : 0;
r 0 0 0 0 : 0 : 1;normal clocking
case
r 0 0 1 1 : ? : -;
r 0 1 1 1 : ? : 0;
r 1 0 1 1 : ? : 1;
r 1 1 1 1 : 0 : 1;
r 1 1 1 1 : 1 : 0;
f ? ? ? ? : ? : -;
b * ? ? ? : ? : -;
b ? * ? ? : ? : -;
endtable
endprimitive
六复杂建模
数组、时延、函数、任务与协议。
1.数组
可用reg、i
nteger、time、real、realtime和向量寄存器等数据类型,线网类型的数组还可以
用来连接多个示例端口;如wire w1[7:0];wire
w2[0:7];的最高位分别为w1[0]、w2[7];
2.延时
检查时序的方式之一是时序仿真,在仿真过程中计算与该模块相关的延迟值;之二是静态
时序验证。
(1)延迟类型
·分布延迟:在每个独立的元件基础上定义一种建模方
式是将延迟值赋给独立的门,另一种
是在单独的assign语句中指定延迟值。
·集总延迟:定义在每个独立模块基础上,表面看来像是模块输出门的当延迟。它比分布延
迟更容易建模
。
·引脚到引脚(即路径)的延迟:分别把延迟赋给模块中从每个输入到每个输出之间的所
有
路径。因此可以针对每条输入输出路径分别指定延迟。对大规模电路而言,它比分布延迟
更容
易建模,设计者只需了解模块的输入输出引脚,无需了解模块内部。
(2)路径延迟
·specify块:
模块路径延迟:在模块的源引脚和目标引脚之间的延迟;在关键字specify和endspecify之间给路径延迟赋值。块中包含:给穿过模块的所有路径指定引脚到引脚的时序延迟,在电路
中设置时
序检查,定义specparam常量。例:
module
M(out,a,b,c,d);
output out;
input a,b,c,d;
wire e,f;
specify
(a=>out)=9;
(b=>out)=9;
(c=>out)=11;
(d=>out)=11;
endspecify
and
a1(e,a,b);
and a2(f,c,d);
and a3(out,e,f);
endmodule
s
pecify块是块中一个独立部分,不在任何其他模块(如initial或always)内出现,内部语<
br>句含义必须非常明确。
·specify块内部:
并行连
接:每条路径语句都有一个源域和一个目标域,每一位都对应相连,如果是向量必
须是相同的位数,如例
中(source=>destination)=;
全连接:位对位
连接,如果源和目标是向量,则不必位数相同,即类似于交叉相连;用法
为:(souce*>dest
ination)=delay_value;例:
wire [31:0] e;
wire [15:0] f;
specify
(a,b *> out)=9;
(c,d *> out)=11;
(e *> f)=9; 相当于32×16=352条并行连接语句的功能;
endspecify
边沿敏感连接:用于输入到输出延迟的时序建模,仅当源信号上出现特定边沿时才有用。
例:
(posedge clock=>(out +: in))=(10:8);
时钟到输出信号用去上升延迟10,数据路径从in到out
下降延迟8;
specparam声明语句:用在specify块中声明特殊参数,为了方便给延迟赋值;例:
specify
specparam d_to_q =9;
specparam clk_to_q =11;
(d=>q)=d_to_q;
(clk=>q)=clk_to_q;
endspecify
条件路径延迟:if句表示,又称状态依赖路径延迟,如:
if (a)
(a=>out) =9;
if (~(a&c)) (b=>out) =10;
if ({c,d}==2'b01) (c,d *> out)=13;拼接操作
上升、下降和关断(turn-off)延迟:可给任意路径定义1个、
2个、3个、6个或12个延
迟参数,其他个数都是错误的;且必须严格按顺序定义;参数有:
t_rise,t_fall,t_turnoff,t_delay,t_01,t_10
,t_0z,t_z1,t_1z,t_z0,t_0x,
t_x1,t_1x,t_x0,t_xz,t_zx;例:
specparam
t_delay=11;
(clk=>q)=t_delay;
specparam
t_rise=9,t_fall=13,t_turnoff=11;上升过程0z->1,
(clk=>q)=(t_rise,t_fall,t_turnoff);
下降过程1z->0,关断过程01->z
specparam t_01=9,t_10
=13,t_0z=11,t_z1=9,t_1z=11,t_z0=13,t_0x=4,
specparam
t_x1=13,t_1x=5,t_x0=9,t_xz=11,t_zx=7;
(clk=>q)=(t_01,t_10,t_0z,t_z1,t_1z,t_z0,t_0x,
t_x1,t_1x,t_x0,t_xz,t_zx);
必须严格按照顺序指定延迟参数
最小值、最大值和典型延迟值:每个延迟可指定3种形式的值min:typ:max,如:
specparam t_rise=8:9:10=11,t_fall=12:13:14,t_t
urnoff=10:11:12;
(clk=>q)=(t_rise,t_fall,turnoff);
处理x状态转换:若没有显示的指定x转换的延迟,则保守的方法规定:
:从x到已知状态转换应当消耗可能的最大时间;
:从已知状态到x态转换应当消耗可能的最小时间;
(3)时序检查
系统任务进行时序检查。$$setup,$$hold,$$width;都只能在specify块里。
·$$setup和$$hold,用来检查设计中时序元件的建立和保持约束。建立时间,是数据必须在有
效时钟边沿之前到达的最小时间;保持时间,是数据在有效时钟边沿之后保持不变的最小时
间。
用法:
$$setup
(被检查的信号,用于检查的参考信号,需要的最小建立时间);
如果(T检-T被检查)<建立时间,则报告违反约束。如:
specify
$$setup (data,posedge clk,3);
endspecify
$$hold
(reference,data,limit);
若(Tdata-Tref)
specify
$$hold (posedge
clr,data,5);
endspecify
·$$width,检查脉冲宽度是否满足最小宽度要求;用法:
$$width(信号的边沿跳变,脉冲最小宽度);
不显示指定data,它是ref信号的下一个反响跳变沿;若(Tdata-Tref)
specify
$$width(posedge clk,6);
endspecify
(4)延迟反标注
流程中使用步骤:
i.设计者写RTL描述,然后进行功能仿真;
ii.逻辑综合工具将RTL描述转换成门级网表;
iii.设计者用延迟计算器和IC制造工艺信息获取芯片制作版图前的延迟估
计,然后进行门级网表的时序仿真或者静态时序验证,初步估计检查门级
网表是否满足要求;
iv.布局布线工具将门级网表转换成版图,根据版图中电阻和电容信息,
计算制作版图后的延迟值,R和C信息是根据几何形状和IC制造工艺提取的
;
v.版图后得到的延迟值反标注到门级网表中,再次时序仿真或静态时序验
证网表;
vi.若要改变设计,则返回RTL级,优化,再重复2~5步。
3.函数和任务
(1)区别
i.任务有或没有入、出和双向变量,函数至少有入变量;
ii.任务可调用另一个任务或函数,函数可调用另一个函数不能调用任务;
iii.任务可在非零仿真时刻执行,函数总在仿真只可0执行;
iv.任务可包含延迟、事件、或时序控制声明语句,函数不能,只能代替纯组合逻辑v代码;
v.任务不返回任何值,可通过output或inout传递多个值;函数只能返回一个值
,不能有输
出变量。
vi.都必须在模块内部定义,可声明局部变量,但不能wire型;
vii.只
能用行为语句,但不能含initial和always块,但可在initial和always块中调用任务
和
函数。
(2)任务
若满足:i.子程序中包含延迟、时序
或者事件控制结构,ii.没有输出或者输出变量数目大于
1个,iii.没有输入变量,
三个中任意一个条件,必须用任务而不能用函数。如:
parameter
delay=10;
reg [15:0]
A,B,AB_ADN,AB_OR,AB_XOR;
always
@(A or B)
begin
bitwise_oper(A
B_AND,AB_OR,AB_XOR,A,B);变量必须按任务定义时的次序
end
task bitwise_oper;
output [15:0]
ab_and,ab_or,ab_xor;
input [15:0] a,b;
begin
#delay ab_and=a&b;
ab_or=a|b;
ab_xor=a^b;
end
endtask
任务本质是静态的,其中所有声
明项的地址分配是静态分配的,同时并发执行的多个任务
共享这些存储区。为避免在不同地方被同时调用
而导致出错,在task前加automatic字,成
为自动可重入任务,这样调用时是动态分配存储
空间,建议使用。如:
task automatic bitwise_oper;
...
endtask
(3)函数
如果一个子程序i.内不含延迟、时序和控制结构,ii.只有一个返回值,iii.至少一个输入
量,
iv.没有输出和双向量,v.不含非阻塞赋值语句,
条件全部成立,则可以使用函数。隐含一个reg型的函数标识符传递输出结果。如:
reg [31:0] addr;地址值
reg
parity;
always @(addr)
begin
parity=calc_parity(addr);第一次启动
$$display(第二次启动
end
function calc_parity;偶校验位计算
input
[31:0] address;
begin
calc_parity=^address;返回所有地址位的异或值
end
endfunction
可以的ANSI C风格的定义:
function calc_parity(input [31:0] address);
begin
calc_parity=^address;返回所有地址位的异或值
end
endfunction
例子,左右移位:根据控制信号每次将一个32位数左或右移移位,
module
shifter;
`define LEFT_SHIFT 1'b0
`define RIGHT_SHIFT 1'b1
reg
[31:0] addr,left_addr,right_addr;
reg
control;
always @(addr)
begin
left_addr=shift(addr,`LEFT_SHIFT);
right_addr=shift(addr,`RIGHT_SHIFT);
end
function [31:0] shift;
input [31:0] address;
input control;
begin
shift=(control==`LEFT_SH
IFT)?(address<<1):(address>>1);
end
endfuncton
endmodule