本文作为SpinalHDL学习笔记第五十七篇,介绍SpinalHDL的SpinalEnum数据类型。
目录:
1.描述(Description)
2.声明(Declaration)
3.操作符(Operators)
⼀、描述(Description)
Enumeration类型代表⼀组值组成的列表。
⼆、声明(Declaration)
枚举数据类型的声明⽅式如下:
object Enumeration extends SpinalEnum {
val element0, element1, ..., elementN = newElement()
}
对于上述例⼦, 使⽤默认的编码⽅式。原⽣的枚举类型⽤于VHDL, ⼆进制编码⽤于Verilog。
能够通过下述⽅式强制使⽤枚举编码:
object Enumeration extends SpinalEnum(defaultEncoding=encodingOfYourChoice) {
val element0, element1, ..., elementN = newElement()
}
Note:如果想为给定的模块定义枚举类型的输入/输出, 应该⽤如下⽅式定义:in(MyEnum())或者out(MyEnum)。
1. 编码(Encoding)
SpinalHDL⽀持下述的枚举编码⽅式:
/*
*静态编码⽅式
*/
object MyEnumStatic extends SpinalEnum {
val e0, e1, e2, e3 = newElement()
defaultEncoding = SpinalEnumEncoding("staticEncoding")(
e0 -> 0,
e1 -> 2,
e2 -> 3,
e3 -> 7
)
/*
*⽤函数动态编码: _ * 2 + 1
*e.g. : e0 => 0 * 2 + 1 = 1
* e1 => 1 * 2 + 1 = 3
* e2 => 2 * 2 + 1 = 5
* e3 => 3 * 2 + 1 = 7
*/
val encoding = SpinalEnumEncoding("dynamicEncoding", _ * 2 + 1)
object MyEnumDynamic extends SpinalEnum(encoding) {
val e0, e1, e2, e3 = newElement()
}
}
2. 举例(Example)
初始化枚举信号并给它赋值:
object UartCtrlTxState extends SpinalEnum {
val sIdle, sStart, sData, sParity, sStop = newElement()
}
val stateNext = UartCtrlTxState()
stateNext := UartCtrlTxState.sIdle
//你也可以import枚举类型使其元素可视化, 需要放在package⾥
import UartCtrlTxState._
stateNext := sIdle
Verilog:
localparam UartCtrlTxState_sIdle = 3'd0;
localparam UartCtrlTxState_sStart = 3'd1;
localparam UartCtrlTxState_sData = 3'd2;
localparam UartCtrlTxState_sParity = 3'd3;
localparam UartCtrlTxState_sStop = 3'd4;
wire [2:0] stateNext;
`ifndef SYNTHESIS
reg [55:0] stateNext_string;
`endif
`ifndef SYNTHESIS
always @(*) begin
case(stateNext)
UartCtrlTxState_sIdle : stateNext_string = "sIdle ";
UartCtrlTxState_sStart : stateNext_string = "sStart ";
UartCtrlTxState_sData : stateNext_string = "sData ";
UartCtrlTxState_sParity : stateNext_string = "sParity";
UartCtrlTxState_sStop : stateNext_string = "sStop ";
default : stateNext_string = "???????";
endcase
end
`endif
assign stateNext = UartCtrlTxState_sIdle;
三、操作符(Operators)
以下是可供Enumeration类型使⽤的操作符:
1. 比较运算(Comparison)
|操作符|描述|返回类型| |x===y|相等|Bool| |x=/=y|不相等|Bool|
import UartCtrlTxState._
val stateNext = UartCtrlTxState()
stateNext := sIdle
when(stateNext === sStart) {
...
}
switch(stateNext) {
is(sIdle) {
...
}
is(sStart) {
...
}
...
}
2. 类型(Types)
为了使⽤你的enum, 例如在函数⾥, 你需要它的类型。
enum中值的类型(例如sIdle的类型):
spinal.core.SpinalEnumElement[UartCtrlTxState.type]
或者等价地, 也可以如下⽅式:
UartCtrlTxState.E
bundle的类型(例如stateNext的类型):
spinal.core.SpinalEnumCraft[UartCtrlTxState.type]
或者等价地, 也可以⽤如下⽅式:
UartCtrlTxState.C
3. 类型转换(Type cast)
import UartCtrlTxState._
val stateNext = UartCtrlTxState()
myBits := sIdle.asBits
stateNext.assignFromBits(myBits)
Verilog:
localparam UartCtrlTxState_sIdle = 3'd0;
localparam UartCtrlTxState_sStart = 3'd1;
localparam UartCtrlTxState_sData = 3'd2;
localparam UartCtrlTxState_sParity = 3'd3;
localparam UartCtrlTxState_sStop = 3'd4;
wire [2:0] myBits;
wire [2:0] stateNext;
wire [2:0] _zz_stateNext;
reg [7:0] counter;
`ifndef SYNTHESIS
reg [55:0] stateNext_string;
reg [55:0] _zz_stateNext_string;
`endif
`ifndef SYNTHESIS
always @(*) begin
case(stateNext)
UartCtrlTxState_sIdle : stateNext_string = "sIdle ";
UartCtrlTxState_sStart : stateNext_string = "sStart ";
UartCtrlTxState_sData : stateNext_string = "sData ";
UartCtrlTxState_sParity : stateNext_string = "sParity";
UartCtrlTxState_sStop : stateNext_string = "sStop ";
default : stateNext_string = "???????";
endcase
end
always @(*) begin
case(_zz_stateNext)
UartCtrlTxState_sIdle : _zz_stateNext_string = "sIdle ";
UartCtrlTxState_sStart : _zz_stateNext_string = "sStart ";
UartCtrlTxState_sData : _zz_stateNext_string = "sData ";
UartCtrlTxState_sParity : _zz_stateNext_string = "sParity";
UartCtrlTxState_sStop : _zz_stateNext_string = "sStop ";
default : _zz_stateNext_string = "???????";
endcase
end
`endif
assign myBits = UartCtrlTxState_sIdle;
assign _zz_stateNext = myBits;
assign stateNext = _zz_stateNext;