1、枚举的介绍
枚举创建了一种强大的变量类型,仅限于一些特定名称的集合,例如指令中的操作码或、状态机中的状态名。例如使用ADD、MOVE、或者ROTW这些名称有利于编写和维护代码。
2、枚举变量的声明
最简单的枚举类型声明包括一个常量名称列表以及一个或多个变量。
enum {RED,BLUE,GREEN} color;
这种方式创建的是一个匿名的枚举类型,它只能用于这个例子中声明的变量。而创建一个署名的枚举变量更方便声明更多的新变量,尤其当这些变量被用作子程序参数或者模块端口的时候。你需要先创建一个枚举类型,再创建相应的变量。
例如:
module enum_text;
typedef enum {INITE,DECODE,IDLE} fsmstate_e;
fsmstate_e pstate,nstate;
initial begin
case(pstate)
IDLE:nstate=INITE;
DECODE:nstate=IDLE;
default:nstate=DECODE;
endcase
$display("the next STATE is% s",
nstate.name());
end
endmodule
3、枚举值的定义
枚举值(枚举声明的常量)在缺省状态下为从0开始递增的整数。但也可以在声明语句中定义默认值。
例如:typedef enum{INITE,DECODE=4,IDLE} fsmstate_e;
上面枚举常量INITE=0;DECODE=4;IDLE=5,这些枚举常量与变量的作用范围和规则是一致的,如果在不同的枚举类型中使用同一常量名,如把INITE用于不同的状态机中,那么你就要在不同的作用域声明他们,如模块、程序块、函数或类。
由于枚举变量被系统默认为int变量,而int类型变量缺省值为0.所以在进行初始化枚举变量的时候要避免以下情况:
typedef enum{INITE=1,DECODE;IDLE} position_e;
position_e position1;
例子中的position1的默认值为0,但这并不是合法的position_e变量。所以这样的枚举值定义是错误的。正确的做法是把0指定给其中一个枚举常量。
typedef enum{BAD_O=0,INITE=1,DECODE,IDLE} position_e;
position_e position1;
4、枚举类型的子程序
枚举类型相关的函数:
enum_e.first(); /返回第一个枚举常量,enum_e 为枚举变量名称;
enum_e.last(); /返回最后一个枚举常量;
enum_e.n xt(); /返回下一个枚举常量;
enum_e.next(N); /返回后面第N个枚举常量;
enum_e.prev(); /返回前一个枚举常量;
enum_n.prev(N); /返回前面第N个枚举常量;
当到达常量列表的最后一个时,next和prev会以环形的方式绕回。用以下方法历所有枚举成员:
typedef enum{RED,GREEN,BLUE,BLACK,WHITE,GRAYE} color_e;
color_e color;
color=color.first;
do begin
$display("color is %0d/%s",color,color.name);
color=color.next;
end while(color!=color.next);
上述代码运行结果如下:
5、枚举类型的转换
由于枚举类型的缺省类型为双状态的int。可以将枚举类型变量直接赋值给int类型变量,但不能将int变量反过来直接赋值给枚举类型变量,除非使用显式类型转换$cast()。否则可能出现数值越界的情况。
注:$cast(a,b); 将b的值赋给a,进行类型检查;
a=type'(b); /将b赋给a,但不进行类型检查;
如下:
typedef enum{RED,BLUE,GREEN}COLOR_E;
COLOR_E color,c2l;
int c;
initial begin
color=BLUE;
c=color;
c++;
if(!$cast(color,c))
$display("Cast failed for c=%0d",c);
else
$display("Cast success for c=%d/%s",color,color.name);
c++;
c21=COLOR_E'(c);
$display("c21 is %0d/%s",c21,c21.name);
end
运行结果如下:
明显第一次显式转换成功,第二次产生数值越界。