-
使用typedef关键字来建立用户自定义类型。一个用户自定义数据类型可以是Verilog语言中任何合法的名称。为了使代码易读并便于维护,一般的命名习惯是使用"_t"作为所有用户自定义类型的结尾。
-
当枚举类型定义从包中导入时,只有类型名被导入,枚举列表中的数值标签不会被导入,所以要使用通配符导入整个包,才能使数值标签可见。
图1:
- 除了指定一组唯一的标签外,SystemVerilog提供了两种便捷方式可以在一个枚举类型列表中指定标签范围。
- state —— 创建单个标签state
- state[N] —— 创建标签序列,state0,state1,…stateN
- state[N:M] —— 创建标签序列,有stateN开始,stateM结束。如果N小于M,序列由N增长至M。如果N大于M,序列由N减小至M。
// 下面的例子创建了一个枚举列表:带有标签RESET,S0~S5,W6~W9
enum {RESET,S[5],W[6:9]} state;
- 缺省情况下,枚举类型列表中的标签代表的实际数值是一个int类型的整数(32位)。枚举列表中的第一个标签表示数值0,第二个标签表示数值1,第三个标签表示数据2,以此类推。并不需要对枚举列表中的每个标签的值进行指定。如果没有指定,每个标签表示的值是前一个标签的值加上1。枚举中的各个标签必须具有唯一的值。如果有两个标签具有相同的值就会出现错误。
// B自动表示2,C自动表示3,Y自动表示25,Z自动表示26
enum {A=1, B, C, X=24, Y, Z} list1;
// C和D具有同样的值,所以错误
enum {A=1, B, C, D=3} list2;
- 枚举类型的默认基类是int,它是32位两态类型。但是也可以对枚举类型的基类进行显示的声明。如果对显示定义枚举类型的枚举标签赋值,那么这个值的宽度必须与基类宽度相符。
enum bit {TRUE,FALSE} Boolean;
enum logic [1:0] {WAIT,LOAD,READY} state;
enum logic [2:0] {
WAIT = 3'b001,
LOAD = 3'b010,
READY = 3'b100
} state
- 将一个与枚举类型声明的基类宽度不同的值赋给一个枚举标签是错误的。如果枚举列表中的标签数超过了基类所能代表的宽度,这也是错误的。
// 下面两个都是错误的,列表数值的宽度和基类宽度不符
enum {
WAIT = 3'b001,
LOAD = 3'b010,
READY = 3'b100
} state;
enum logic {A=1, B, C} list;
-
由typedef声明的枚举类型一般被称作为自定义枚举类型,可以用来声明几个具有相同枚举值的变量或线网。不使用typedef定义的则称作匿名枚举类型。
-
当对一个枚举类型数值进行操作时,枚举数值自动转换成代表枚举类型列表中标签的基类和内部值。
typedef enum {WAIT,LOAD,READY} state_t;
state_t state,next_state;
int foo;
// 下面的是合法操作
state = next_state;
// 下面的也是合法操作
foo = state + 1;
// 下面的就是错误的。不是同一个枚举类型的值赋给一个枚举变量,就是错误的。
state = foo + 1;
state = state + 1; // 不合法操作,因为state+1就是int类型,不是枚举类型了
state++; // 不合法操作
next_state += state; // 不合法操作
- SystemVerilog提供了一些内置函数,可以循环访问枚举类型列表中的值。
- <枚举变量名>.first
- <枚举变量名>.last
- <枚举变量名>.next
- <枚举变量名>.prev
- <枚举变量名>.num
- <枚举变量名>.name —— 表示当前枚举变量的值对应的标签名
// 获取当前状态的值的标签名
$display("current state's value is %s",State.name);
- 使用枚举类型变量给状态机建模:
module traffic_light (
output logic green_light,
yellow_light,
reg_light,
input sensor,
input [15:0] green_downcnt,
yellow_downcnt,
input clock,resetN
);
enum bit [2:0] {
RED = 3'b001,
GREEN = 3'b010,
YELLOW = 3'b100
} State, Next;
always_ff @(posedge clock, negedge resetN)
begin
if(!resetN) State <= RED;
else State <= Next;
end
always_comb
begin: set_next_state
Next = State;
unique case(State)
RED: if(sensor) Next = GREEN;
GREEN: if(green_light == 0) Next = YELLOW;
YELLOW: if(yellow_light == 0) Next = RED;
endcase
end: set_next_state
always_comb
begin: set_outputs
{green_light, yellow_light, reg_light} = 3'b000;
unique case(State)
RED: reg_light = 1'b1;
GREEN: green_light = 1'b1;
YELLOW: yellow_light = 1'b1;
endcase
end: set_outputs
endmodule