文章目录
内容:这篇文章的主要是为了描述枚举类型的定义,为什么需要枚举类型,以一个例子说明枚举类型的基类型,以另外一个例子说明枚举类型的重要性
提示:以下是本篇文章正文内容,下面案例可供参考
一、枚举类型
1.枚举类型值
缺省情况下,枚举类型列表中的标签代表的实际数值是一个int类型的整数,枚举列表中的第一个标签代表数值0,第二个名称表示1,第三个表示数值2,以此类推。 举例如下:enum {A=1,B,C,X=24,Y,Z} list1;
标签A被显式的赋值为1,B自动地表示2,C表示3。X的数值被显式地定义为24,Y和Z分别表示25和26。
枚举列表中的各个标签必须具有唯一的值,如果有两个标签具有相同的值就会出现错误,下面的例子将会产生一个错误,因为C和D具有同样的数值3.
enum {A=1,B,C,D=3} list2; //错误
2.枚举类型的基类
枚举类型是具有以系列标签值的变量或线网,因此,枚举类型具有一个Verilog或Systemverilog基类。枚举类型的默认基类是int,它是32位两态类型。
//1位宽的枚举类型,两态基类
enum bit {TRUE,FALSE} Boolean;
//2位宽的枚举类型,四态基类
enum logic[1:0] {WAIT,LOAD,READY} state;
如果对显式定义枚举类型的枚举标签赋值,那么这个值的宽度必须与基类宽度相符。
enum logic[2:0] {WAIT=3'b001,
LOAD=3'b010,
READY=3'b100} state;
将一个与枚举类型声明的基类宽度不同的值赋给一个枚举标签是错误的,下面的例子就是错误的,enum变量默认为int基类,给标签赋给一个3位值就会发生错误。
enum {WAIT =3'b001,
LOAD = 3'b010,
READY =3'b100} state;
这是错误的,因为int类型是32位,但是其中的枚举元素的变量宽度是3位的,违背值的宽度与基类宽度相符的规定。
如果枚举列表中的标签超过了基类所能代表的宽度,这是错误的。
enum logic {A=1'b0,B,C} list5 //错误,对于1位宽度来说
//只能为0和1
如果枚举值的基类是四态数据类型,将枚举标签赋为X或者Z是合法的。
enum logic{ON=1'b1,OFF=1'bz} out;
如果X或者Z赋值给枚举列表中的一个标签,下一个必须显式地赋值,试图由赋为X或者Z的标签的值加1来自动获得值是错误的。
enum logic[1:0]{WAIT,ERR=2'bxx,LOAD,READY}state;
//错误,不能确定LOAD的值
二、枚举类型使用举例
1.使用传统verilog语言define和parameter编写状态机的代码
代码如下(示例):
`define FETCH 3'h0
`define WRITE 3'h1
`define ADD 3'h2
`define SUB 3'h3
`define MULT 3'h4
`define DIV 3'h5
`define SHIFT 3'h6
`define NOP 3'h7
module controller(output reg read,write,
input wire [2:0] instruction
input wire clock,resetN);
parameter WAITE=0,
LOAD=1,
STORE=2;
reg [1:0] state,next_state;
always @(posedge clk,negedge resetN)
if(!resetN)
state <= WAITE;
else
state <= next_state;
always @(state) begin
case(state)
WAITE : next_state= LOAD;
LOAD : next_state= STORE;
STORE : next_state= WAITE;
endcase
end
always @(state,instruction)begin
read=0; write=0;
if(state==LOAD && instruction == `FETCH)
read=1;
else if(state == STORE&&instruction==`WRITE)
write=1;
end
endmodule
这是仿真波形
这个是利用verilog撰写的代码,使用常数值的变量,如这个例子中的state和next_state,必须声明为标准的Verilog变量类型,这意味着软件工具无法限定这些信号的有效值仅仅是这些常数数值,在这个例子上,没有采用什么方法来限制state和next_state有一个值3,或者有一位或多位被设置成X或者Z的值,因此,模型本身必须加入对这些值的限定检验,至少,需要一个综合的“full case”编译指令来综合工具,状态变量只使用case列表中的常数值,然而,综合编译指令的使用并不影响仿真,这可能会引起仿真行为和由综合产生的结构级设计并不相同。
2.使用systemverilog 枚举类型 enum撰写代码
从图中可以看出仿真结果正常,使用systemverilog撰写上述代码package chip_type;
typedef enum {FETCH, WRITE, ADD, SUB, MULT, DIV, SHIFT, NOP} instr_t;
endpackage;
import chip_type::*;
module sv_5(
output logic read, write,
input instruction,
input clk, resetN);
enum {WAIT,LOAD,STORE} state,next_state;
always @(posedge clk or negedge resetN)
begin
if(!resetN)
state <= WAIT;
else
state <= next_state;
end
always @(state)
begin
case(state)
WAIT: next_state=LOAD;
LOAD: next_state=STORE;
STORE: next_state=WAIT;
endcase
end
always @(state,instruction)
begin
read=0; write=0;
if(state == LOAD && instruction == `FETCH)
read=1;
else if(state == STORE && instruction ==`WRITE)
write=1;
end
endmodule
testbench
`timescale 1ns/1ns
import chip_type::*;
module sv_5_tb;
logic clk,resetN;
instr_t instruction;
wire read,write;
sv_5 u1(.instruction(instruction),
.read(read),
.write(write),
.clk(clk),
.resetN(resetN));
always #5 clk= ~clk;
initial
begin
clk=0;
instruction=FETCH; //FETCH
resetN=0;
#20
resetN=1;
#2000
$finish;
end
endmodule
仿真波形
在这个例子中,变量State和Next_state只能有WAITE、LOAD、和STORE三种有效值,所有的软件工具,包括仿真、综合和形式验证都用相同的方式解释对于枚举类型变量合法值的约束,所以systemverilog撰写的case语句中不需要加入default,也不会生成锁存器。
分析利用systemverilog仿真的波形,read与write的数值是不定态,而且state,next_state的数值也没有发生更新,这是为什么呢??
always块建立的组合逻辑不会在零时刻自动触发,
这是因为state是枚举类型,枚举类型的缺省值是int两态数据类型,所以默认初始值是0,0时刻复位没有任何变化,所有不会触发。
总结
通过举例可以发现,枚举类型enum的引入带来了以下优点:(1)systemverilog引入了枚举类型enum之后,简化了代码的复杂度,使得代码便于维护和调试。
(2)使用systemverilog enum枚举类型可以避免锁存器的产生,但是使用verilog撰写的代码必须设置default的缺省值选项,否则会生成锁存器。