第二章:数据类型与编程结构

SV新增了二值逻辑:byte bit int shortint longint

四值逻辑:integer logic reg net

有符号数:byte integer int shortint longing

无符号数:bit logic reg net

logic可以代替reg,但不能用在双向总线和多驱动的情况下,而只能用wire

枚举类型:enum

enum [date_type] {name1=value1,name2=value2,...nameN=valueN} var_name

Var_name(枚举类型名)的缺省类型默认为int,name1,name2...nameN为枚举名,可以为任意常量值,或者从0递增的值,枚举变量不能被枚举集合范围以外的数值直接赋值,除非使用强制类型转换。但枚举变量可以转换成整型值,用在表达式中,或者赋值给其他兼容的变量。

用户定义类型:typedef

Typedef int my_favorite_type;其实用户定义类型并未产生新的结构类型,只是做了文本替换。

typedef常常与struct enum union class相结合使用。

数组(静态数组、动态数组、关联数组)与队列:

  1. 静态数组(定宽数组):

允许编程者定义每一维是如何存储的,分为压缩数组和非压缩数组(又称合并型、非合并型)

压缩数组的维数定义在变量标识符之前:bit [7:0] c1;

非压缩数组的维数定义在变量标识符之后:bit c2 [7:0];

通用定义:

element_date_type[prange1]...[prangeN]array_name[urange1]...[urangeN]

其中array_name之前的维数为压缩部分,之后的维数为非压缩部分。

压缩数组赋值不需要用‘,而非压缩的需要’

int array[0:7][0:31];  //通过范围来定义数组
int array[8][32];      //通过指定上限定义数组

注意:压缩数组类型只能是无符号类型(bit logic reg net),而有符号类型(integer byte int shortint longint)不能定义压缩数组,压缩数组的维数必须从高到低。

integer i1;  //就如logic signed[31:0] i1; integer为32位有符号类型
byte c2[4:0];  //就如bit signed [7:0] c2 [4:0]; byte为8位有符号类型

bit [3:0][7:0]reg_32; //压缩数组
bit [3:0][7:0]mix_array[3];//非压缩数组

2.动态数组

声明动态数组:date_type array_name[];

空的 “ [ ] ” 意味着我们不需要在编译的时候指定数组的大小, 在运行的过程中可以动态分配。 动态数组初始定义时是空的, 没有分配任何空间, 使用前必须通过调用 new [ ] , 并在“ [ ] ” 中输入期望的长度数值来分配空间。 动态数组属于非压缩型,赋值需要‘

Size()、delete()函数只能对动态数组使用,而不能对静态数组使用

3.关联数组

地址空间不连续,索引号可以是数据类型或者整型表达式

4.队列

队列是一个大小可变,具有相同数据类型的有序集合。可以在队头或队尾3进行插入或删除操作。队列中的每一个成员都通过一个序号来标识,其中0代表队列中的第一个成员,$代表队列中的最后一个成员。类似于动态数组,不需要使用new分配空间,是一个一维的非压缩数组,赋值要用’。

定义:date_type quene_name[$];或date_type quene_name [$:maxsize];

maxsize表示队列成员的最大个数。

空文本[]表示空队列,且在声明的时候没有赋初值,则队列也是一个空队列。

 

字符串类型(string):是一个大小可变、动态分配的字节数组,字符串文本是一个压缩数组,其宽度为8的整数倍。字符串文本赋值到长度不同的压缩数组时,被截断或者左侧补0。

语法声明:string varible_name[=initial_value];

例:string s;//声明字符串,没有赋值,属于空字符串

String s = “tom”;//声明s为字符串类型,其值为”tom”

结构体(typedef struct)和联合体(typedef union):

使用packed关键可以把结构体变为类似于压缩数组的压缩结构体。如下图:

 

packed后面可以跟signed或unsigned表示结构体成员的符号属性,缺省值为无符号数.

压缩结构体成员内只要有一个4值逻辑,所有成员都会强制变成四值逻辑,压缩结构体中每一位数据都可以使用[n-1:0]的编号方法来访问,非整型数组类型(real,shortreal)不可以使用在压缩结构体中,压缩联合体中的成员位宽必须一致。

常量:

三个细化时间(elaboration-time)常量:parameter,localparam,specparam

一个运行时间(run-time)常量:const

1.parameter参数:参数在定义时必须给定初值,可以定义成任何数据类型:

Parameter [date_type] para_name = default_value;

Parameter string file_name=”test_case1”;

一个整型参数可以使用$赋值,$表示没有上限的边界,最大值可以是任意整数。

  1. localparam本地参数:不能通过defpapram修改和例化时修改,可以在generate模块,package模块,class内部定义使用
  2. specparam延时参数:只能在延时说明块(specify block)中出现,且只能定义延时参数
  3. const常量:经过const关键字定义的常量为静态常量

文本表示:

1.整数表示:

Date_wide ’ base date 其中date_wide为位宽,可不写。若采用‘作为前缀,则说明一个文本的所有位都可以使用相同的数来填充;

 

2.字符串表示:

字符串文本由双引号包围,且对字符串的长度没有限制,但一个字符串文本次序存在一个单行中。

3.结构体表示

在定义结构体变量后,对结构体中的成员赋值有多种方式,大多采用嵌套花括号形式,注意非压缩结构体赋值需要’。而对于结构体数组的赋值需要将每一对数值用嵌套花括号包起来,

①此外,结构体赋值还可以使用成员名和成员值的方式:c=’{a:0,b:0.0};

②还可以采用数据类型赋值:d=ab’{int:1,shortreal:1.0};该语句指明了数据类型以及这种数据类型成员的缺省值

③结构体赋值还可以使用缺省值赋值:c=’{default:0}//默认结构体c中所有元素为0;

4、数组表示:

数组或结构体的赋值都可以使用复制操作符,如:

Int n[1:2][1:3]=’{‘{0,1,2},{3{4}}};//复制操作符

同样的,数组赋值还可以使用索引或数据类型或缺省值作为操作数:

Trible b=’{1:1,default:0};//索引1为1,其余默认为0

5、时间表示

时间文本使用的数值和后面的时间单位之间没有空格,时间文本被解释成realtime类型的值

操作符:

SV新增操作符:通配操作符,有符号移位,动态移位

  1. 通配操作符:在verilog中,相等(==)和不相等(!=)会逐位比较两个操作数,若操作数出现x或z,结果就是x,而全等(===)和非全等(!==)比较操作会一位一位的对比,通配操作符(==?通配等于和!=?和通配不等于)会忽略操作数中的xz不进行比较。
  2. 有符号移位:<<<有符号左移,>>>有符号右移
  3. 动态移位:往往是对数组成员进行操作:动态向右[I + : C],动态向左[I- : C]

过程语句

每个过程模块都由过程语句构成,过程语句顺序执行,SV中共有6种过程语句:

赋值语句、条件选择语句、循环语句、跳转语句、子程序调用语句、事件控制。

赋值语句

阻塞赋值=、非阻塞赋值=>、自加/自减赋值++/--、过程连续赋值assign,其中自加和自减与过程连续赋值为SV新增的,过程连续赋值包括对变量或线网的assign、deassign、和force、release。

条件选择语句

If...else;case...endcase;

注意:case的条件表达式与分支表达式做的比较是全等比较(===)而不是相等比较(==)

SV也提供了casex与casez,其中,casex条件表达式种的x都不参与比较,casez条件表达式中的所有x、z都不参与比较

:循环语句

for循环:verilog中的for循环,循环变量必须在循环体之前说明,如果程序中有并发进程,可能会与循环体共用该循环变量,造成功能错误,因此sv添加了声明for循环控制变量的能力:

在verilog中:int i;for(i=0;i<255;i++)...;在SV中:for(int i;i<255;i++)

此外verilog只允许单个初始化语句(第一个位置)和单个步值赋值语句(第三个位置),而SV中允许有多个初始化语句和多个赋值语句,用逗号隔开即可。

即for(int count=0,done=0,j=0;j*count<125;j++,count++)

while语句:(while(expression) begin...end)

do...while语句:(至少执行一次循环体)

repeat语句:需要配合begin...end.若表达式为x或z,则认为循环0次,不执行循环体,形式为:repeat(expression) begin...end

forever语句:forever begin...end。为防止forever语句无限循环导致仿真挂起,内部必须含有时序控制或者disble语句

foreach语句:foreach循环指定数组后,会自动遍历每个数组成员,数组可以是静态、动态或者关联数组。声明:foreach(array_name[loop_variablea])

跳转语句

break:跳出本层循环

continue:跳转到本次循环尾部

return(expression):退出函数,并返回函数值

return:退出一个任务或者void函数

子程序调用:函数和任务

函数和任务的区别:任务没有返回值,而函数可以有。任务可以带时序,而函数不行。函数不能调用任务。

在函数或者任务中的语句块顺序执行,因此可以不用begin...end,且函数或者任务中没有任何执行语句也是合法的。

参数定义主要有两个:首先定义方向,其次定义类型。Sv中缺省类型为logic,缺省方向为input,一旦指定了一个方向,就会成为后续参数的缺省方向。

例如一个task的定义:

task mytask(input int x,output int y)...endtask//方向和类型均有定义

task mytask2(a,b,output bit [15:0] u,v)...endtask//a,b没有指定,缺省方向为input,v在u之后,缺省方向跟随u为output。

数据方向共有4种:input:在开始时复制值;output:在结束时复制值;inout:在开始时复制,结束时输出;ref:传递引用(句柄或指针)。

若在函数或任务指定缺省值,则在子程序调用是可以不用传递参数

task mytask3(ref int x,input int a=0,input int b=1)...endtask。由于a和b的缺省值已定义好,因此在调用mytask3这个任务时可以不用传递a,b这两个参数。

子程序返回

函数和任务返回时的区别:

1、verilog中任务或者函数遇到endtask,endfunction的时候退出,而在sv中,可以使用return语句在任务体或函数体的任意一点退出子程序。

2、verilog中,函数必须有返回值,且返回值是通过对函数名赋值来完成的,或者使用return来指定返回值,而在SV中可以将函数声明成void类型,即无返回值函数。

3、在sv中函数可以返回一个结构体或者联合体,则函数内部可以使用以函数名为起始的层次化名。

4、普通函数的调用都以表达式的形式被调用,而void类型的函数可以单独作为一个语句调用:

 

自动存储

在sv中,所有的模块或者程序块中,子程序默认采用静态存储方式,而声明在类中的子程序和变量默认是动态存储的。

注意:动态存储的变量不能够使用非阻塞赋值(<=)

编程结构:模块、程序块、过程块、数据对象

模块

顶层模块的输入输出端口代表电路的输入输出端口,顶层模块由若干个子模块构成,子模块通过端口相互连接,端口连接方式有三种:采用*对同名信号做默认连接,端口名称关联,端口位置关联。

程序块

程序块可以实行三个基本目标:提供验证程序执行入口;提供封装验证程序数据、函数、任务的结构;提供一个语法来指定在reactive区域中的调度执行。

一个程序块包括:类型和数据声明、子程序、与设计的连接、一个或多个过程化的代码。

声明:

program test(input clk ,inout[7:0]data)//括号中也可以是ineerface device_ifc

Initial...

Endprogram

程序块可以嵌套在模块或者接口内部,但程序块内部不能包含always、udp、module、interface或其他程序块的定义或例化。程序块中可以有任务、 函数、 类和 initial 块, 但不能有 always 块 。

过程块和语句块

除了连续赋值(assign)以外,模块主要由过程块构成,包括:initial、always(always_comb、always_ff、always_latch)、finial。

Initial在程序开始时执行。final在所有进程结束后执行,always在敏感条件满足时开始运行,敏感条件不满足时被挂起。

过程块可以串行执行(begin...end)也可以并行执行(fork...Join),SV还添加了两种变形(fork...join_any、fork...join_none)

数据对象

数据对象有:interface、class和其他普通的数据类型

模块端口中除了input、output、inout以外,也像子程序调用那样增加了ref

此外SV增加了一个重要的数据类型:interface,其作用主要有两个,一是简化模块端口连接,二是实现类和模块之间的通信。

接口为硬件端口提供了一个标准化的封装方式:例如PCI、ARM、AHB等都是标准的接口。

interface的定义是独立于模块的,通过关键字interface,endinterface包括起来,interface里面还可以带时钟、断言、方法等定义。

类型转换:

静态类型转换:使用强制类型转换操作符(‘):type’(expression)

例如:int’(2.0*3.0);   shortint’(8’hFA.8’hCE);   signed’(x);  mytype’(foo);//mytype为用户定义类型;  16’(2)//改变位宽

注意:改变符号或者位宽时,表达式必须是整型值。Shoretreal类型转换为int或者32位时会进行四舍五入操作,进而丢失精度。

静态转换是在编译时运行的转换操作,而不会检查结果的有效性

动态类型转换:$cast系统函数,可以作为任务或者函数进行调用

作为函数调用时:function int $cast(singular dest_var,singular source_exp);cast试图将源表达式赋值给目标变量,如果复制成功,则返回1,如果不成功则不进行赋值操作,且返回0.

作为任务调用时:task $cast (singular dest_var,singular source_exp);如果赋值有效则将源表达式赋值给目标变量,如果赋值无效则运行时报错,且目标变量保持不变。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 顺序存储结构中数据中数据元素之间逻辑关系是由( )表示的,链接存储结构中的数据元素之间的逻辑关系是由( )表示的。 A.线性结构 B.非线性结构 C.存储位置 D.指针 2. 线性表是( )。 A.一个有限序列,可以为空 B. 一个有限序列,不能为空 C. 一个无限序列,可以为空 D. 一个无限序列,不能为空 3. 已知一维数组A采用顺序存储结构,每个元素占用4个存储单元,第9个元素的地址为144,则第一个元素的地址是( )。 A. 108 B. 180 C. 176 D. 112 4. 在单链表中删除指针p所指结点的后继结点,则执行( )。 A. p->next= p->next->next B. p->next= p->next C. p= p->next->next D. p= p->next; p->next= p->next->next 5. 若某链表最常用的操作是在最后一个结点之后插入一个结点删除最后一个结点,则采用( )存储方式最节省时间。 A. 单链表 B. 双链表 C. 带头结点的双循环链表 D. 单循环链表 6.二维数组A[7][8]以列序为主序的存储, 计算数组元素A[5][3] 的一维存储空间下标 k=( )。 A. 38 B. 43 C. 26 D. 29 二、完成下列填空题(每空3分,共9分)。 1.在顺序表L中第i个位置上插入一个新的元素e: Status ListInsert_Sq(SqList &L , int i , ET e){ if ( iL.length+1) return ERROR; if(L.length >= L.listsize){ p=(ET*)realloc(L.elem,(L.listsize+10)*sizeof(ET)); if (p==NULL) exit(OVERFLOW); L.elem=p; } for( j=L.length ; j>=i ; --j ) L.elem[j]=L.elem[j-1] ; L.elem[j]=e ; ++L.length ; return OK; } 2. 删除双向链表中p所指向的节点算法: status delete(DuLinkList L, DuLinkList p) { if (p= =L) return ERROR; else { p->prior->next=p->next; p->next->prior=p->prior ; } free(p); return OK; } 三、编程题(共27分)。 1. (共12分)用顺序表表示集合,设计算法实现集合的求差集运算,要求不另外开辟空间。 顺序表的存储结构定义如下: #define Maxsize 100 typedef struct { ElemType data[MaxSize]; // ElemType表示不确定的数据类型 int length; // length表示线性表的长度 }SqList; 将如下函数,伪码补充完整(8分),代码前先用文字描述自己的算法思想(4分)。 文字描述算法:略(4分) void Difference(SqList A, SqList B) {//参考代码如下如下(8分) for (i=0;i<A.length;i++) for(j=0;j<B.length;j++) if(A.data[i]==B.data[j]) { A.data[i]=’#’; break; } for (k=0,i=0;inext == L) return; p = L; while (p->next != L)   { if (p->next->data != e) P = p->next; else { q = p->next;p->next = q->next; free(q);} } } 时间复杂度分析:(2分) 时间复杂度为O(n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值