Chinaunix首页 | 论坛 | 博客
  • 博客访问: 393674
  • 博文数量: 128
  • 博客积分: 2247
  • 博客等级: 大尉
  • 技术积分: 767
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-17 09:30
文章分类

全部博文(128)

文章存档

2011年(4)

2010年(124)

我的朋友

分类: 嵌入式

2010-07-28 19:50:34

概述

      行为级模型是使用行为建模方法实现的,这种描述主要考虑一个模块的抽象功能描述,而不考虑其具体实现(具体电路结构由综合工具得到);门级模型是对电路的具体描述,主要是描述与、或、非等基本电路的连接方式;开关级建模则更加接近“底层”,它把最基本的MOS晶体管连接起来实现电路功能。

       门级建模和开关级建模在verilog中都属于结构建模方法,因为它们的建模风格都是对电路结构的具体描述。结构建模简单说就是把需要的基本电路单元(逻辑门、MOS开关等)调出来,再用连线把这些基本单元连接起来。这种描述是简单而又严格的,之所以这样说一方面是因为这些语句只需要说明“某一个门电路或MOS管的某个端口”与“另一个门电路或MOS管的某个端口”相连就可以了,另一方面是因为这种建模方式要求设计者必须对基本门电路和MOS管的功能及连接方式熟悉,否则只要一个端口连错就会使整个模块无法工作。

       用于结构建模的这些门电路和MOS开关是电路中的基本元件,称之为基元。verilog已经内置26个基元的模型,可以直接调用这些基元进行建模。基元的调用又称为“实例化”,调用语句也称为实例语句,每次基元调用都将产生这个基元的一个实例,应该为该实例起一个名字,即实例名。

       除了内置的26个基元,verilog还允许用户自己定义基元,即UDP,这些UDP的用法和内置基元完全相同,定义起来也很方便。

4.1 verilog内置基元

       上面提到的26个基元可以分类如下:

·多输入门     and, nand, or, nor, xor, xnor

·多输出门      buf, not

·三态门         bufif0, bufif1, notif0, notif1

·上拉、下拉电阻   pullup, pulldown

·MOS开关 cmos, nmos, pmos, rcmos, rnmos, rpmos

·双向开关 tran, tranif0, tranif1, rtran, rtranif0, rtranif1

使用这些基元进行结构建模的语法形式如下:

primitive_type[instance_name](term1, term2, .........,termN);

其中,primitive_type是26个基元之一,如and、cmos;instance_name是基元的实例名,是可选项。不同的基元输入输出端口的数量和功能都不同,termN表示输入输出端口。

4.1.1 内置基本门

(1)多输入门

       多输入门有1个或多个输入,单只有单个输出。共有6种:

and   nand   nor   or   xor   xnor

其实例语句的语法格式如下:

multiple_input_gate_type[instance_name](OutputA, Input1, Input2, .........InputN);

(2) 多输出门

多输出门可以有一个或多个输出,但是只有一个输入。verilog内置了两种多输出门:

·buf   缓冲门

·not   非门

多输出门的语法形式如下:

multiple_output_gate_type[instance_name](Out1, Out2, ......, OutN, InputA);

(3)三态门

       三态门用于对三态驱动器建模,共有三个端口:一个数据输入端、一个控制信号输入端和一个数据输出端。verilog内置了4种三态门:

bufif0     bufif1     notif0   notif1

1表示控制信号不取反,0表示控制信号取反。bufif表示输出不取反,notif表示输出取反。三态门的语法形式如下:               tristate_gate[instance_name] (OutputA, InputB, ControlC);

4.1.2 上拉、下拉电阻

       上拉电阻和下拉电阻是一类只有一个端口的(输出端)的器件模型,其作用是改变其输出端的值:上拉电阻将输出置为1,下拉电阻将输出置为0。声明上拉电阻和下拉电阻的关键词是:pullup和pulldown。

4.1.3 MOS开关

       MOS晶体管可以说是集成电路最底层的元件,做模拟模拟集成电路设计的工程师们整天都在和MOS管打交道,用HDL设计数字集成电路时,某些情况下也需要用到MOS开关模型作为单向开关。MOS模型在仿真时表现为两种状态,开或关,即导通或不导通,所以MOS可作为开关使用。对于MOS来说,数据只能从输入端流向输出端,并且可以通过设置控制信号来关闭数据流,所以MOS是单向的。verilog内置了6种MOS开关: cmos   pmos   nmos   rcmos   rpmos   rnmos  

       其中,pmos、nmos、rnmos和rpmos都是三端口MOS开关,包括一个数据输出端、一个数据输入端和一个控制信号端。语法形式如下:

mos_type[instance_name](OutputA, InputB, ControlC);

与nmos和pmos相比,rnmos和rpmos唯一的不同是其在输入端和输出端之间存在阻抗。因此对于rpmos和rnmos,当数据从输入端传输至输出端时,由于电阻带来的损耗,使得数据的信号强度减弱。

      cmos和rcmos(cmos的高阻态版本)有4个端口:一个数据输出端,一个数据输入端和两个控制信号输入端。其形式如下:

(r)cmos[instance_name](OutputA, InputB, NControl, PControl);

4.1.4 双向开关

      6个双向开关:tran   rtran   tranif0 rtranif0   tranif1   rtranif1

      其中,前两个开关tran和rtran是不能关断的,始终处于打开状态,数据可以在两个端口之间自由流动。其语法格式如下:(r)tran[instance_name] (SignalA, SignalB);       

因为没有控制信号,着两个开关都不能被关断。这有什么意义呢?

       后四个双向开关语法如下:

bidirdection_type[instance_name] (SignalA, SignalB, ControlC);

这里ControlC是控制信号。

4.1.5 给基元定义时延

       门时延定义可以出现在门自身实例语句中,形式如下:

primitive_type [delay] [instance_name](terminal_list);

       定义门时延也可以采用另外一种形式“minimum:typical:maximum”。如:

nand #(2:3:4, 5:6:7)(Pout, Pin1, Pin2);

其中,2:3:4给出了上升时延的3个备选值,5:6:7给出了下降沿时的备选值。

4.1.6 描述实例数组

4.1.7 内置单元建模实例

4.2 用户定义基元

       verilog提供了一种扩展基元的方法,允许用户自己定义基元,即UDP。UDP的逻辑功能可以比较复杂,可以把一块组合逻辑电路或时序逻辑电路封装在一个UDP内,并把这个UDP作为一个基元来使用,所以UDP可以分为组合电路UDP和时序电路UDP。

       注意:UDP在任何情况下都是不能综合的,仅能用于仿真。

4.2.1 UDP的定义

        在语法上,UDP定义和模块定义是同级的,所以UDP定义不能出现在模块之内。UDP定义可以单独出现在一个verilog文件中或与模块定义同时处于某个文件中。

      模块定义使用一对关键词“primitive-endprimitive”封装起来的一段代码,这段代码定义该UDP的功能,这种功能的定义是通过表来实现的,即在这段代码中有一段处于关键词“table-endtable”之间的表,用户可以通过设置这个表来规定UDP的功能。此外,UDP可以有一个或多个输入端,但是只能有一个输出端,其形式如下:

primitive UDP_name(OutputName, List_of_inputs)

Output_declaration

List_of_input_declarations

[Reg_declaration]

[Initial_statement]

table

      List_of_table_entries

endtable

endprimitive

Verilog规定,UDP的输入如果出现z值就当作x处理。

在UDP中可以描述两类电路行为:

·组合电路;

·时序电路(边沿触发型和电平触发型)。

4.2.2 组合电路UDP

       组合逻辑电路的功能列表类似真值表,就是规定了不同的输入值和对应的输出值,表中每一行的形式是“Input1, Input2, ……是输入端的值,排列顺序和端口列表中的顺序相同。如果某个输入组合没有定义的输出,那么就把这种情况的输出置为x。UDP的使用方法和内置基元完全相同。

4.2.3   时序电路UDP

       UDP除了可以描述组合电路外,还可以描述具有电平触发和边沿触发特性的时序电路。时序电路拥有内部状态状态序列,其内部状态必须用寄存器变量进行建模,该寄存器的值就是时序电路的当前状态,它的下一个状态是由放在基元功能列表中的状态转换表决定的,而且寄存器的下一个状态就是这个时序电路UDP的输出值。

        所以,时序电路UDP由两部分组成——状态寄存器和状态列表。定义时序UDP的工作也分为两部分——初始化状态寄存器和描述状态列表。

(1)初始化状态寄存器

        可以使用带有一条过程赋值语句的初始化语句实现时序电路UDP的状态寄存器初始化,形式如下:

initial reg_name = 0,1, or x;

其中,reg_name是状态寄存器,0、1、x是这个寄存器可以取的值。初始化状态寄存器并不是必须出现的,若在UDP定义中没有状态寄存器初始化语句,那么状态寄存器的值为x。

(2)电平触发的时序电路UDP

(3)边沿触发的时序电路

4.2.4 Verilog速记符号

4.2.5 电平触发和边沿触发混合的UDP

4.3 模块实例化

        调用低层子模块把所有模块连接成整个电路或者高层模块时,要使用模块实例化语句。模块实例化语句和调用基元实例化语句形式上完全一致,也是使用结构建模方法描述的。这种层次化引用子模块方法的形式如下: module_name instance_name(port_associations);   其中port_associations是端口关联声明。

4.3.1 端口关联声明

       子模块的输入输出端口应该连接到高层模块中,完成这种连接的是高层模块中的线网和寄存器,其连接方式可以是“位置关联方式”和名称关联方式,二者形式如下:

port_expr                         //位置关联方式

.PortName(port_expr)     //名称关联方式

        Portname是子模块定义时给出的端口名称,port_expr是高层模块内定义的线网或寄存器变量,这个变量与子模块端口关联就实现了子模块与高层模块的连接。

        在位置关联方式中,不需要给出子模块定义时给出端口名称PortName,只要把相应的prot_expr按指定的顺序排列就能和子模块的端口关联,这个排列顺序必须和子模块定义时给出的端口顺序相同。

4.3.2 悬空端口

       在模块实例化语句中,允许端口出现悬空,可以将端口表达式表示为空白来指定悬空端口。看下例:

module DFF(Q, Qbar, Data, Preset, Clock);

output Q, Qbar;

input Data, Preset, Clock;

..............

endmodule

在高层模块中两次调用DFF模块,模块实例化语句如下:

DFF d1(.Q(Q), Qbar( ), .Data(D), .Preset( ), .Clock(CK) );   //名称关联方式,其中输出端口Qbar和输入端口Preset的括号里都是空的,表明这两个端口被悬空。

DFF d2(QS, ,D, , CK);   //位置关联方式,输出端口Qbar和输入端口Preset的位置空白,被悬空。

4.3.3 端口匹配

       在端口关联时,如果出现关联端口长度不同的情况,处理方式是通过无符号数的右对齐并截断的方式进行匹配。

4.3.4 模块参数值

       如果子模块内定义了参数,当这个子模块被引用时,高层模块能够改变子模块的参数值。改变模块参数值可以采用两种方式:参数定义语句(使用关键词defparam)和带参数值的模块引用。

(1)参数定义语句

       参数定义语句需要使用关键词defparam,其形式如下:

defparam hier_path_name1 = value1, hier_path_name2 = value2, ..........;看下面的例子:

子模块半加器的描述如下:

module HA(A, B, S, C);

input A, B;

output S, C;

parameter AND_DELAY = 1, XOR_DELAY = 2;   //定义了两个参数

assign #XOR_DELAY S = A^B

assign #AND_DELAY C = A&B

endmodule

高层模块描述如下:

module TOP(NewA, NewB, NewS, NewC);

input NewA, NewB;

output NewS, NewC;

defparam ha1.XOR_DELAY = 5, ha1.AND_DELAY = 2;

HA ha1(NewA, NewB, NewS, NewC);

end module

在这个高层子模块中,引用了子模块HA,并将其实例命名为ha1,通过defparam语句给ha1的连个参数重新赋值。

(2)代参数值的模块引用

在这种方法中,模块实例化语句自身包含有新的参数值。实现方式如下:

HA #(5,2) HA1(NewA, NewB, NewS, NewC);

给出参数值的方式是“#(5,2)”,形式上与时延定义相似,但意义完全不同。在这种方式中,模块实例化语句中参数值的顺序必须与子模块中声明参数的顺序相同。

阅读(5274) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~