SpinalEnum

一、描述(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()
}

备注:如果想为给定的模块定义枚举类型的输入/输出, 应该用如下方式定义:in(MyEnum())或者out(MyEnum)

  1. 编码(Encoding)

    SpinalHDL支持下述的枚举编码方式:

编码方式 Bit位宽 描述
native 这是默认编码方式, 使用VHDL枚举系统
binarySequential log2Up(stateCount) 以声明的顺序使用Bits存储状态(值从0到n-1)
binaryOneHot stateCount 使用Bits来存储状态, 每个bit对应一个状态

定制化的编码方式能用静态和动态的方式实现:

/*
 *静态编码方式
 */
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()
    }
}
  1. 举例(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)

操作符 描述 返回类型
x.asBits 二进制转换为Bits Bits(w(x) bits)
x.asUInt 二进制转换为UInt UInt(w(x) bits)
x.asSInt 二进制转换为SInt SInt(w(x) bits)
e.assignFromBits(bits) Bits转换为enum MyEnum()
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;