Verilog小叙(二)

来源:互联网 发布:淘宝客广告文案 编辑:程序博客网 时间:2024/06/02 12:17

好的,接着上篇文章

常量

Verilog HDL中有三种常量:
整型、实型、字符串型。
下划线符号“_”可以随意用在整数或实数中,它们就数量本身没有意义。它们能用来提高易读性;唯一的限制是下划线符号不能用作为首字符。
下面主要介绍整型和字符串型。

整型

整型数可以按如下两种方式书写:
1. 简单的十进制数格式
2. 基数格式

简单的十进制格式

这种形式的整数定义为带有一个可选的“+”(一元)或“-”(一元)操作符的数字序列。
下面是这种简易十进制形式整数的例子。
32 十进制数32
-15 十进制数-15

基数表示法

这种形式的整数格式为:
[size ] ‘base value
size 定义以位计的常量的位长;
base 为o或O(表示八进制),b或B(表示二进制),d或D(表示十进制),h 或H (表示十六进制)之一;
value 是基于base 的值的数字序列。值x和z以及十六进制中的a 到f 不区分大小写。
下面是一些具体实例:

5 'o37 //5位八进制数(二进制11111)4 'd2 //4位十进制数(二进制0011)4 'b1x_01 //4位二进制数7 'hx //7位x(扩展的x), 即xxxxxxx4 'hz //4位z(扩展的z) , 即zzzz4 'd-4 //非法:数值不能为负3' b 001 //非法:和基数b之间不允许出现空格(2+3)'b10 //非法:位长不能够为表达式

注意,x(或z)在十六进制值中代表4位x(或z),在八进制中代表3位x(或z ),在二进制中代表1位x(或z)。
基数格式计数形式的数通常为无符号数。这种形式的整型数的长度定义是可选的。如果没有定义一个整数型的长度,数的长度为相应值中定义的位数。下面是两个例子:
‘o 7219 3位八进制数
‘h AF8 4位十六进制数

如果定义的长度比为常量指定的长度长,通常在左边填0补位。但是如果数最左边一位为x 或z,就相应地用x 或z 在左边补位。例如:
10'b10左边添0占位,0000000010
10'bx0x1左边添x占位, xxxxxxx0x1
如果长度定义得更小,那么最左边的位相应地被截断。例如:
3 ' b1001_00113'b011相等
5'H0FFF5'H1F相等

字符串型

字符串是双引号内的字符序列。字符串不能分成多行书写。
例如:
"INTERNAL ERROR"
" REACHED->HERE "
用8位ASCII值表示的字符可看作是无符号整数。因此字符串是8位ASCII 值的序列。为存储字符串“INTERNAL ERROR”,变量需要8*14位。
reg [1:8*14] Message;

Message = "INTERNAL ERROR"

数据类型

Verilog HDL 主要包括两种数据类型
1. 线网类型(net type)

  1. 寄存器类型(reg type)

线网类型

  1. wire 和 tri 定义

线网类型主要有wire 和tri两种。线网类型用于对结构化器件之间的物理连线的建模.如器件的管脚,内部器件如与门的输出等。以上面的加法器为例,输入信号A,B是由外部器件所驱动,异或门X1的输出S1是与异或门X2输入脚相连的物理连接线,它由异或门X1所驱动。简单地讲,S1由X1驱动。
由于线网类型代表的是物理连接线,因此它不存贮逻辑值。必须由器件所驱动。通常由assign进行赋值。如 assign A = B ^ C;
当一个wire 类型的信号没有被驱动时,缺省值为Z(高阻)。
信号没有定义数据类型时,缺省为 wire 类型。
如上面一位全加器的端口信号 A,B,SUM等,没有定义类型,故缺省为wire 线网类型。
两者区别
tri主要用于定义三态的线网。

寄存器类型

  1. 定义
    reg 是最常用的寄存器类型,寄存器类型通常用于对存储单元的描述,如D型触发器、ROM等。存储器类型的信号当在某种触发机制下分配了一个值,在分配下一个值之时保留原值。
    reg 类型定义语法如下:
reg [msb: lsb] reg1, reg2, . . . reg N;msb 和lsb 定义了范围,并且均为常数值表达式。范围定义是可选的;如果没有定义范围,缺省值为1 位寄存器。例如:reg [3:0] Sat; // Sat 为4 位寄存器。reg Cnt; //1 位寄存器。reg [1:32] Kisp, Pisp, Lisp ;//寄存器类型的值可取负数,但若该变量用于表达式的运算中,则按无符号类型处理,如:reg A ;.....A = -1;....则A的二进制为1111,在运算中,A总按 无符号数15来看待。
  1. 寄存器类型的存储单元建模举例
    用寄存器类型来构建两位的D触发器如下:
reg [1:0] dout ;.....always@(posedge clk)dout <= din;....用寄存器数组类型来建立存储器的模型,如对2个8位的RAM建模如下:reg [7:0] mem[0:1] ;对存储单元的赋值必须一个个第赋值,如上2个8位的RAM的赋值必须用两条赋值语句:.....mem[0] = ’ h 55;mem[1] = ’ haa;....
  1. 书写规范建议
    对数组类型,请按降序方式,如[7:0] ;
    Tips:
    reg的类型不一定是寄存器,只有带有时钟的always块才能是寄存器,不带时钟的always块是组合逻辑。

运算符和表达式

Verilog HDL中的操作符可以分为下述类型:

  1. 算术操作符

  2. 关系操作符

  3. 相等操作符

  4. 逻辑操作符

  5. 按位操作符

  6. 归约操作符

  7. 移位操作符

  8. 条件操作符

  9. 连接和复制操作符

下表显示了所有操作符的优先级和名称。操作符从最高优先级(顶行)到最低优先级(底行)排列。同一行中的操作符优先级相同。

算术运算符

在常用的算术运算符主要是 :

  • 加法(二元运算符):“+”;

  • 减法 (二元运算符):“-”;

  • 乘法(二元运算符):“*”;

在算术运算符的使用中,注意如下两个问题:

  1. 算术操作结果的位数长度

算术表达式结果的长度由最长的操作数决定。在赋值语句下,算术操作结果的长度由操作符左端目标长度决定。考虑如下实例:

reg [3:0] arc, bar, crt;reg [5:0] frx;. . .arc = bar + crt;frx = bar + crt;

第一个加的结果长度由bar,crt 和 arc 长度决定,长度为4位。
第二个加法操作的长度同样由frx 的长度决定(frx 、bat 和crt 中的最长长度),长度为6位。
在第一个赋值中,加法操作的溢出部分被丢弃;而在第二个赋值中,任何溢出的位存储在结
果位frx [ 4 ]中。
在较大的表达式中,中间结果的长度如何确定?在Verilog HDL 中定义了如下规则:表达式中的所有中间结果应取最大操作数的长度(赋值时,此规则也包括左端目标)。考虑另一个实例:
wire [4:1] box, drt;
wire [5:1] cfg;
wire [6:1] peg;
wire [8:1] adt;

assign adt = (box + cfg) + (drt + peg) ;
表达式右端的操作数最长为6 ,但是将左端包含在内时,最大长度为8 。所以所有的加操作使用8 位进行。例如:box 和cfg 相加的结果长度为8 位。
2. 有符号数和无符号数在设计中,请先按无符号数进行。

关系运算符

关系运算符有:
- ?>(大于)

  • ?<(小于)

  • ?>=(不小于)

  • ?<=(不大于)

  • = = (逻辑相等)

  • = (逻辑不等)

关系操作符的结果为真(1 )或假(0 )。如果操作数中有一位为X 或Z ,那么结果为X 。
例:
23 > 45
结果为假(0 ),而:
52 < 8’hxFF
结果为x 。
如果操作数长度不同,长度较短的操作数在最重要的位方向(左方)添0 补齐。例如:
‘b1000 > = ‘b01110
等价于:
‘b01000 > = ‘b01110
结果为假(0 )。
在逻辑相等与不等的比较中,只要一个操作数含有x 或z,比较结果为未知 (x),如:
假定:
Data = ‘b11x0;
Addr = ‘b11x0;
那么:
Data = = Addr 比较结果不定,也就是说值为x 。

逻辑运算符

逻辑运算符有:
&& (逻辑与)
|| (逻辑或)
!(逻辑非)
用法为:(表达式1) 逻辑运算符 (表达式2) ….
这些运算符在逻辑值0(假) 或1(真) 上操作。逻辑运算的结果为0 或1 。例如, 假定:
crd = ‘b0; //0 为假
dgs = ‘b1; //1 为真
那么:
crd && dgs 结果为0 (假)
crd || dgs 结果为1 (真)
!dgs 结果为0 (假)

按位逻辑运算符

按位运算符有:
?~(一元非):(相当于非门运算)
?&(二元与):(相当于与门运算)
?|(二元或): (相当于或门运算)
?^(二元异或):(相当于异或门运算)
?~ ^, ^ ~(二元异或非即同或):(相当于同或门运算)
这些操作符在输入操作数的对应位上按位操作,并产生向量结果。
例如,假定,
A = ‘b0110;
B = ‘b0100;
那么:
A | B 结果为0110
A & B 结果为0100
如果操作数长度不相等, 长度较小的操作数在最左侧添0补位。例如,
‘b0110 ^ ‘b10000
与如下式的操作相同:
‘b00110 ^ ‘b10000
结果为’b10110。

条件运算符

条件操作符根据条件表达式的值选择表达式,形式如下:
cond_expr ? expr1 : expr2
如果cond_expr 为真(即值为1 ),选择expr1 ;如果cond_expr 为假(值为0 ),选择expr2 。如果cond_expr 为x 或z ,结果将是按以下逻辑expr1 和expr2 按位操作的值: 0 与0 得0 ,1 与1 得1 ,其余情况为x 。
如下所示:
wire [2:0] student = marks > 18 ? grade_a : grade_c;
计算表达式marks > 18; 如果真,grade_a 赋值为student;如果marks < =18, grade_c 赋值为student 。

连接运算符

连接操作是将小表达式合并形成大表达式的操作。形式如下:
{expr1, expr2, …,exprN}
实例如下所示:
wire [7:0] Dbus;
assign Dbus [7:4] = {Dbus [0], Dbus [1], Dbus[2], Dbus[ 3 ]};
//以反转的顺序将低端4 位赋给高端4 位。
assign Dbus = {Dbus [3:0], Dbus [7:4]};
//高4 位与低4 位交换。
由于非定长常数的长度未知, 不允许连接非定长常数。例如,下列式子非法:
{Dbus,5} //不允许连接操作非定长常数。

条件语句

if 语句的语法如下:

if(condition_1)procedural_statement_1{else if(condition_2)procedural_statement_2}{elseprocedural_statement_3}

如果对condition_1 求值的结果为个非1,那么procedural_statement_1 被执,如果condition_1 的值为0 、x 或z ,那么procedural_statement_1 不执行。如果存在一个else 分支,那么这个分支被执行。

if (sum < 60) begingrade = c;//串行语句total_c = total _c + 1;endelse if(sum < 75) begingrade = b;total_b = total_b + 1;endelse begingrade = a;total_a = total_a + 1;end

若为if - if 语句,请使用块语句 begin — end :

if(clk == 1) beginif (reset== 1)q = 0;elseq = d;end

对if语句,除非在时序逻辑中,if 语句需要有else语句。若没有缺省语句,设计将产生一个锁存器,锁存器在asic设计中有诸多的弊端。
如下一例:
if (t == 1)
q = d;
没有else 语句,当t为1(真)时,d 被赋值给q,当t为0(假)时,因为没有else 语句,电路保持 q 以前的值,这就形成一个锁存器。

case语句

case 语句是一个多路条件分支形式,其语法如下:

case(case_expr)case_item_expr{ ,case_item_expr} :procedural_statement. . .. . .[default:procedural_statement]endcase

case 语句首先对条件表达式case_expr 求值,然后依次对各分支项求值并进行比较,第一个与条件表达式值相匹配的分支中的语句被执行。可以在1 个分支中定义多个分支项;这些值不需要互斥。缺省分支覆盖所有没有被分支表达式覆盖的其他分支。

case (HEX)4'b0001 : led = 7'b1111001; // 14'b0010 : led = 7'b0100100; // 24'b0011 : led = 7'b0110000; // 34'b0100 : led = 7'b0011001; // 44'b0101 : led = 7'b0010010; // 54'b0110 : led = 7'b0000010; // 64'b0111 : led = 7'b1111000; // 74'b1000 : led = 7'b0000000; // 84'b1001 : led = 7'b0010000; // 94'b1010 : led = 7'b0001000; // a4'b1011 : led = 7'b0000011; // b4'b1100 : led = 7'b1000110; // c4'b1101 : led = 7'b0100001; // d4'b1110 : led = 7'b0000110; // e4'b1111 : led = 7'b0001110; // fdefault : led = 7'b1000000; // 0endcase

case 的缺省项必须写,防止产生锁存器。

只有组合逻辑才可能产生锁存器,时序逻辑不会产生锁存器。

结构建模

模块定义结构

我们已经了解到,一个设计实际上是由一个个module 组成的。一个模块module 的结构如下:
module module_name (
port_list
) ;
Declarations_and_Statements
endmodule
在结构建模中,描述语句主要是实例化语句,包括对Verilog HDL 内置门如与门(and)异或门(xor)等的例化,如全加器的xor 门的调用;及对其他器件的调用,这里的器件包括FPGA厂家提供的一些宏单元以及设计者已经有的设计。
在实际应用中,实例化语句主用指后者,对内置门建议不采纳,而用数据流或行为级方式对基本门电路的描述。
端口队列port_list 列出了该模块通过哪些端口与外部模块通信,在Verilog 2001语法中还包括输入输出、wire/reg类型、位宽定义。

模块端口

模块的端口可以是输入端口、输出端口或双向端口。缺省的端口类型为线网类型(即wire 类型)。输入端口默认为wire类型,不需要定义,输出或双向端口能够声明为wire/reg 型,使用reg必须显式声明,使用wire也强烈建议显式声明。
Verilog 2001语法中的输入输出包括端口名、输入输出、wire/reg类型、位宽定义,极大的减少了端口声明占用的代码行数。当前已经非常普及。
例子:

module LED (//inputinput sys_clk , //system clock;input sys_rst_n , //system reset, low is active;//outputoutput reg [7:0] LED );

该例子包括输入、输出、姓名名称、位宽、输出的信号类型。

实例化语句

一个模块能够在另外一个模块中被引用,这样就建立了描述的层次。模块实例化语句形式如下:

module_name instance_name(port_associations);

信号端口可以通过位置或名称关联;

但是关联方式不能够混合使用。端口关联形式如下:

  • PortName //通过位置。

  • .PortName (port_expr) //通过名称。

建议使用名称进行关联。

// instantance RR_CORERR_CORE U_RR_CORE (.rr_en ( rr_en ),.port_vld ( key ),.last_sel_port ( last_sel_port ),.port_win ( port_win ));

port_expr 可以是以下的任何类型:

  1. 标识符(reg 或net )如 .C(T3),T3为wire型标识符。

  2. 位选择 ,如 .C(D[0]),C端口接到D信号的第0bit 位。

  3. 部分选择 ,如 .Bus (Din[5:4])。

  4. 上述类型的合并,如 .Addr({ A1,A2[1:0]}。

  5. 表达式(只适用于输入端口),如 .A (wire Zire = 0 )。

建议:
在例化的端口映射中请采用名字关联,这样,当被调用的模块管脚改变时不易出错。

悬空端口的处理

在我们的实例化中,可能有些管脚没用到,可在映射中采用空白处理,如:

DFF U_DFF_0 (.q(qs),.qbar ( ), //管脚悬空.data (d ) ,.preset ( ), // 该管脚悬空.clock (ck)); //名称对应方式。

对输入管脚悬空的,则该管脚输入为高阻 Z,输出管脚被悬空的,该输出管脚废弃不用。
建议:
大规模电路设计的时候,悬空的端口最好使用XX_nc(wire类型)进行显式声明,提高检视代码的效率。

不同端口长度的处理

当端口和局部端口表达式的长度不同时,端口通过无符号数的右对齐或截断方式进行匹配。

module Child (Pba, Ppy) ;input [5:0] Pba;output [2:0] Ppy;. . .endmodulemodule Top;wire [1:2] Bdl;wire [2:6] Mpr;Child C1 (Bdl, Mpr) ;endmodule

在对Child 模块的实例中,Bdl[2]连接到Pba[ 0 ],Bdl[1] 连接到Pba[ 1 ],余下的输入端口Pba[5]、Pba[4]、Pba[2]和Pba[3]悬空,因此为高阻态z 。与之相似,Mpr[6]连接到Ppy[0],Mpr[5]连接到Ppy[1],Mpr[4] 连接到Ppy[2]。

结构化建模具体实例

对一个数字系统的设计,我们采用的是自顶向下的设计方式。可把系统划分成几个功能模块,每个功能模块再划分成下一层的子模块。每个模块的设计对应一个module,一个module 设计成一个verilog HDL 程序文件。因此,对一个系统的顶层模块,我们采用结构化的设计,即顶层模块分别调用了各个功能模块。下面以一个实例(一个频率计数器系统)说明如何用HDL进行系统设计。
在该系统中,我们划分成如下三个部分:2输入与门模块,LED显示模块,4位计数器模块。系统的层次描述如下:

顶层模块CNT_BCD,文件名CNT_BCD.v,该模块调用了低层模块 AND2、CNT_4b和HEX2LED 。
顶层模块CNT_BCD对应的设计文件 CNT_BCD.v 内容为:

module CNT_BCD (// ------------ Port declarations --------- //input CLK,input GATE,input RESET,output wire [3:0] BCD_A,output wire [3:0] BCD_B,output wire [3:0] BCD_C,output wire [3:0] BCD_D) ;// ----------- Signal declarations -------- //wire NET104;wire NET124;wire NET132;wire NET80;// -------- Component instantiations -------//CNT_4b U0(.CLK(CLK),.ENABLE(GATE),.FULL(NET80),.Q(BCD_A),.RESET(RESET));AND2 U6(.A0(NET104),.A1(NET124),.Y(NET132));endmodule

Tips:

这里的AND2是为了举例说明,在实际设计中,对门级不要重新设计成一个模块,同时对涉及保留字的(不管大小写)相类似的标识符最好不用。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 50岁睡不着觉怎么办 不会睡觉了怎么办啊 专转本不成功怎么办 斐讯手环w1丢了怎么办 被罩拉链拉不合怎么办 拉链拉不合怎么办图解 塑料拉链不顺畅怎么办 隐形拉链不好拉怎么办 房东赶租客走怎么办 南京合租一间怎么办租房补贴 大学登错成绩怎么办 网游停服花了钱怎么办 北斗星x5油耗高怎么办 北斗星空调不凉怎么办 踏板摩托车费油怎么办 lol队友一直送怎么办 电脑信号无连接怎么办 电脑屏不全屏怎么办 电脑桌面不能显示全屏怎么办? 电脑黑屏无信号怎么办 笔记本电脑屏幕不显示怎么办 手机登录认证要怎么办 360手机丢失了怎么办 主播周年庆怎么办 学校选课系统进不去怎么办 选课系统关闭了怎么办 政府工作人员被威胁怎么办 报志愿忘记用户名怎么办 账号密码忘记了怎么办 商盟卡过期了怎么办 香港身份证掉了怎么办 简易注销有异议怎么办 左转红灯直行了怎么办 怀孕初期吃螃蟹怎么办 天下霸图打不过传闻怎么办 怀孕后期阴部痛怎么办 胎儿头大腿短怎么办 孕期大腿根疼怎么办 到工作单位催债怎么办 被讨债公司骚扰怎么办 要债人上门不走怎么办