UInt/SInt

一、描述(Description)

UInt/SInt数据类型是一个能用在有/无符号计算中的bits向量

二、声明(Declaration)

声明整型的语法如下所示:([]中的是可填项)

语法 描述 返回类型
UInt[()]
SInt[()]
创建有/无符号整型, bits个数编译器推断得到 UInt
SInt
UInt(x bits)
SInt(x bits)
创建x bits的有/无符号整型 UInt
SInt
U(value: Int[, xbits])
U(value: BigInt[, x bits])
S(value: Int[, x bits])
S(value: BigInt[, x bits])
创建有/无符号整型, 并赋值'value' UInt
SInt
U"[[size']base]value"
S"[[size']base]value"
创建有/无符号整型, 并赋值'value'(基:h, d, o, b) UInt
SInt
U([x bits, ] element, ...)
S([x bits, ] element, ...)
创建有/无符号整型, 赋值由element决定 UInt
SInt
val myUInt = UInt(8 bits)
myUInt := U(2, 8 bits)
myUInt := U(2)
myUInt := U"0000_0101"  //基默认二进制
myUInt := U"h1A"        //x/h->基16, d->基10, o->基8, b->基2
myUInt := U"8'h1A"
myUInt := 2             //可以使用Scala Int作为字面值

val myBool := myUInt === U(7 -> true, (downto 0) -> false)
val myBool := myUInt === U(myUInt.range -> true)

//在赋值的时候, 可以去掉U/S, 也支持[default -> ???]
myUInt := (default -> true)                 //赋值“11111111”
myUInt := (myUInt.range -> true)            //赋值“11111111

myUInt := (7 -> true, default -> false)     //赋值“10000000”
myUInt := ((4 downto 1) -> true, default -> false)  //赋值“00011110”
  wire       [7:0]    myUInt;
  reg        [7:0]    _zz_myBool;
  wire                myBool;

  function [7:0] zz__zz_myBool(input dummy);
    begin
      zz__zz_myBool[7] = 1'b1;
      zz__zz_myBool[6 : 0] = 7'h0;
    end
  endfunction
  wire [7:0] _zz_1;

  assign myUInt = 8'h02;
  assign myUInt = 8'h02;
  assign myUInt = 8'h05;
  assign myUInt = 8'h1A;
  assign myUInt = 8'h1A;
  assign myUInt = 8'h02;
  
  assign _zz_1 = zz__zz_myBool(1'b0);
  always @(*) _zz_myBool = _zz_1;
  assign myBool = (myUInt == _zz_myBool);

  assign _zz_myBool[7 : 0] = 8'hff;
  assign myBool = (myUInt == _zz_myBool);
  assign myUInt = 8'hff;
  assign myUInt = 8'hff;
  assign myUInt = 8'h80;
  assign myUInt = 8'h1E;

三、操作符(Operators)

下面是UIntSInt支持的操作符:

  1. 逻辑运算(Logic)##这里有问题##

操作符 描述 返回类型
x ^ y 逻辑异或 Bool
~x 按位取非 T(w(x) bits)
x & y 按位与 T(max(w(x), w(y)) bits)
x | y 按位或 T(max(w(x), w(y)) bits)
x ^ y 按位异或 T(max(w(x), w(y)) bits)
x.xorR x的所有bits取异或 Bool
x.orR x的所有bits取或 Bool
x.andR x的所有bits取与 Bool
x >> y 算术右移, y: Int T(w(x)-y bits)
x >> y 算术右移, y: UInt T(w(x) bits)
x << y 算术左移, y: Int T(w(x)+y bits)
x << y 算术左移, y: UInt T(w(x)+max(y) bits)
x |>> y 逻辑右移, y: Int/UInt T(w(x) bits)
x |<< y 逻辑左移, y: Int/UInt T(w(x) bits)
x.rotateLeft(y) 逻辑循环左移, y: UInt/Int T(w(x) bits)
x.rotateRight(y) 逻辑循环右移, y: UInt/Int T(w(x) bits)
x.clearAll[()] 清除所有bits
x.setAll[()] 置位所有bits
x.setAllTo(value: Boolean) 根据给定Boolean值置位
x.setAllTo(value: Bool) 根据给定Bool值置位

备注:x rotateLeft yx rotateRight y也是有效语句

备注:注意x >> 2x >> U(2)的区别, 前者返回类型是T(w(x)-2), 后者返回类型是T(w(x)), 其次更重要的是, 前者的2视为Int后者的U(2)视为硬件信号。

val a, b, c = SInt(32 bits)
a := S(5)
b := S(10)

//比特级操作
c := ~(a & b)
assert(c.getWidth == 32)

//移位
val arithShift = UInt(8 bits) << 2  //结果10 bits
val logicShift = UInt(8 bits) |<< 2 //结果8 bits
assert(arithShift.getWidth == 10)
assert(logicShift.getWidth == 8)

//循环移位
val rotated = UInt(8 bits) rotateLeft 3
assert(rotated.getWidth == 8)

//当a全1, b也全1
when(a.andR) { b.setAll() }

Verilog:

wire       [31:0]   _zz_c;
wire       [31:0]   a;
reg        [31:0]   b;
wire       [31:0]   c;
wire       [7:0]    _zz_arithShift;
wire       [9:0]    arithShift;
wire       [7:0]    _zz_logicShift;
wire       [7:0]    logicShift;
wire       [7:0]    _zz_rotated;
wire       [7:0]    rotated;
wire                when_MyTopLevel_l51;

assign _zz_c = (a & b);
assign a = 32'h00000005;
always @(*) begin
    b = 32'h0000000a;
    if(when_MyTopLevel_l51) begin
        b = 32'hffffffff;
    end
end

assign c = (~ _zz_c);
assign arithShift = ({2'd0,_zz_arithShift} <<< 2);
assign logicShift = (_zz_logicShift <<< 2);
assign rotated = {_zz_rotated[4 : 0],_zz_rotated[7 : 5]};
assign when_MyTopLevel_l51 = (&a);
  1. 运算(Arithmetic)

操作符 描述 返回类型
x+y 加法 T(max(w(x), w(y)) bits)
x+^y 产生进位加 T(max(w(x), w(y))+1 bits)
x+|y 饱和判断加 T(max(w(x), w(y)) bits)
x-y 减法 T(max(w(x), w(y)) bits)
x-^y 产生借位减 T(max(w(x), w(y))+1 bits)
x-|y 饱和判断减 T(max(w(x), w(y)) bits)
x*y 乘法 T(max(w(x), w(y)) bits)
x/y 除法 T(w(x)bits)
x%y 取模 T(w(x)bits)
val a, b, c = UInt(8 bits)
a := U"xf0"
b := U"x0f"

c := a + b
assert(c === U"8'xff")

val d = a +^ b
assert(d === U"9'x0ff")

val e = a +| U"8'x20"
assert(e === U"8'xff")

Verilog:

wire       [7:0]    a;
wire       [7:0]    b;
wire       [7:0]    c;
wire       [8:0]    d;
wire       [8:0]    _zz_e;
reg        [7:0]    e;
wire                when_UInt_l119;
reg        [7:0]    counter;

assign a = 8'hf0;
assign b = 8'h0f;
assign c = (a + b);
assign d = ({1'b0,a} + {1'b0,b});
assign _zz_e = ({1'b0,a} + {1'b0,8'h20});
assign when_UInt_l119 = (|_zz_e[8 : 8]);
always @(*) begin
    if(when_UInt_l119) begin
        e = 8'hff;
    end else begin
        e = _zz_e[7 : 0];
    end
end

备注:需要注意的是, 该例程的仿真assert用的是===, 而相对的上一例程中细化assert用的是==

  1. 对比操作(Comparison)

操作符 描述 返回类型
x===y 相等 Bool
x=/=y 不相等 Bool
x>y 大于 Bool
x>=y 大于等于 Bool
x<y 小于 Bool
x<=y 小于等于 Bool
val a = U(5, 8 bits)
val b = U(10, 8 bits)
val c = UInt(2 bits)

when (a > b) {
    c := U"10"
} elsewhen (a =/= b) {
    c := U"01"
} elsewhen (a === U(0)) {
    c.setAll()
} otherwise {
    c.clearAll()
}

Verilog:

wire       [7:0]    a;
wire       [7:0]    b;
reg        [1:0]    c;
wire                when_MyTopLevel_l39;
wire                when_MyTopLevel_l41;
wire                when_MyTopLevel_l43;
reg        [7:0]    counter;

assign a = 8'h05;
assign b = 8'h0a;
assign when_MyTopLevel_l39 = (b < a);
always @(*) begin
    if(when_MyTopLevel_l39) begin
        c = 2'b10;
    end else begin
        if(when_MyTopLevel_l41) begin
            c = 2'b01;
        end else begin
            if(when_MyTopLevel_l43) begin
                c = 2'b11;
            end else begin
                c = 2'b00;
            end
        end
    end
end

ssign when_MyTopLevel_l41 = (a != b);
assign when_MyTopLevel_l43 = (a == 8'h0);
  1. 类型转换(Type cast)

操作符 描述 返回类型
x.asBits 二进制转换成Bits Bits(w(x) bits)
x.asUInt 二进制转换成UInt UInt(w(x) bits)
x.asSInt 二进制转换成SInt SInt(w(x) bits)
x.asBools 转换成Bool数组 Vec(Bool, w(x))
S(x:T) 把数据转换成SInt SInt(w(x) bits)
U(x:T) 把数据转换成UInt UInt(w(x) bits)
x.intoSInt 扩展符号位转换成SInt SInt(w(x)+1 bits)

Bool, Bits, SInt转化成UInt可以用U(something), 将类型转化为SInt的时候可以用S(something)

//把SInt转换成Bits
val myBits = mySInt.asBits

//创建一个Bool量
val myVec = myUint.asBools

//把Bits转换成SInt
val mySInt = S(myBits)

Verilog:

wire       [7:0]    mySInt;
wire       [7:0]    myUInt;
wire       [7:0]    myBits;
wire                myVec_0;
wire                myVec_1;
wire                myVec_2;
wire                myVec_3;
wire                myVec_4;
wire                myVec_5;
wire                myVec_6;
wire                myVec_7;

assign myBits = mySInt;
assign myVec_0 = myUInt[0];
assign myVec_1 = myUInt[1];
assign myVec_2 = myUInt[2];
assign myVec_3 = myUInt[3];
assign myVec_4 = myUInt[4];
assign myVec_5 = myUInt[5];
assign myVec_6 = myUInt[6];
assign myVec_7 = myUInt[7];

assign mySInt = myBits;
  1. 提取比特位(Bit extraction)

操作符 描述 返回类型
x(y) 读第y bits的值 Bool
x(offset, width) 读bit区域, offset: UInt, width: Int T(width bits)
x(range) 读某范围内bits, 例如myBits(4 downto 2) T(range bits)
x(y):=z 赋值某bit, y:Int/UInt Bool
x(offset, width):=z 赋值bit区域, offset:UInt, width:Int T(width bits)
x(range):=z 赋值某范围内bits, 例如myBits(4 downto 2):=U"010" T(range bits)
//取第4bit数据
val myBool = myUInt(4)

//把第1bit赋值为True
mySInt(1) := True

//范围内赋值
val myUInt_8bits = myUInt_16bits(7 downto 0)
val myUInt_7bits = myUInt_16bits(0 to 6)
val myUInt_6bits = myUInt_16bits(0 until 6)

mySInt_8bits(3 downto 0) := mySInt_4bits

Verilog:

wire       [7:0]    myUInt;
reg        [7:0]    mySInt;
wire       [15:0]   myUInt_16bits;
reg        [7:0]    mySInt_8bits;
wire       [3:0]    mySInt_4bits;
wire                myBool;
wire       [7:0]    myUInt_8bits;
wire       [6:0]    myUInt_7bits;
wire       [5:0]    myUInt_6bits;

assign myUInt_16bits = {8'd0, myUInt};
assign myBool = myUInt[4];
assign myUInt_8bits = myUInt_16bits[7 : 0];
assign myUInt_7bits = myUInt_16bits[6 : 0];
assign myUInt_6bits = myUInt_16bits[5 : 0];
always @(*) begin
    mySInt_8bits[3 : 0] = mySInt_4bits;
    mySInt_8bits[7 : 4] = 4'b0000;
end

always @(posedge clk or posedge reset) begin
    if(reset) begin
        mySInt <= 8'h0;
    end else begin
        mySInt[1] <= 1'b1;
    end
end
  1. Misc

操作符 描述 返回类型
x.getWidth 返回bit位数 Int
x.msb 返回最高有效位 Bool
x.lsb 返回最低有效位 Bool
x.range 返回区间范围(x.high到0) Range
x.high 返回x的上限 Int
x##y 数据拼接, x->高位, y->低位 Bits(w(x)+w(y) bits)
x@@y 数据拼接, x:T, y:Bool/SInt/UInt T(w(x)+w(y) bits)
x.subdivideln(y slices) 把x切片成y份, y:Int Vec(T,y)
x.subdivideln(y bits) 把x按y bits切片, y:Int Vec(T,w(x)/y)
x.resize(y) 返回x的长度变换后的复制, UInt长度增大补零, SInt长度增大补符号位, y:Int T(y bits)
x.resized 返回按需自动确定长度的x T(w(x) bits)
myUInt.twoComplement(en:Bool) 用补码把UInt转换成SInt SInt(w(myUInt)+1)
mySInt.abs 返回UInt类型的绝对值 UInt(w(mySInt),bits)
mySInt.abs(en:Bool) 如果en是True返回UInt类型的绝对值 UInt(w(mySInt),bits)
mySInt.sign 返回最高有效位 Bool
x.expand 返回1bit拓展后的x T(w(x)+1 bits)
mySInt.absWithSym 返回对称收缩1 bit的UInt的绝对值 UInt(w(mySInt)-1 bits)
myBool := mySInt.lsb    //等价于mySInt(0)

//拼接
val mySInt = mySInt_1 @@ mySInt_1 @@ myBool
val myBits = mySInt_1 ## mySInt_1 ## myBool

//分块
val sel = UInt(2 bits)
val mySIntWord = mySInt_128bits.subdivideIn(32 bits)(sel)
//sel = 0 => mySIntWord = mySInt_128bits(128 downto 96)
//sel = 1 => mySIntWord = mySInt_128bits(95 downto 64)
//sel = 2 => mySIntWord = mySInt_128bits(63 downto 32)
//sel = 3 => mySIntWord = mySInt_128bits(31 downto 0)

//如果想要反向访问数据:
val myVector = mySInt_128bits.subdivideIn(32 bits).reverse
val mySIntWord = myVector(sel)

//变换大小
myUInt_32bits := U"32'x11223344"
myUInt_8bits := myUInt_32bits.resized   //长度自动推断(myUInt_8bits=0x44)
myUInt_8bits := myUInt_32bits.resize(8) //变换为8 bits(myUInt_8bits=0x44)

//取补码
mySInt := myUInt.twoComplement(myBool)

//取绝对值
mySInt_abs := mySInt.abs

Verilog:

wire       [15:0]   _zz_mySInt;
reg        [31:0]   _zz_mySIntWord;
wire       [31:0]   _zz_mySIntWord_1;
wire       [31:0]   _zz_mySIntWord_2;
wire       [31:0]   _zz_mySIntWord_3;
wire       [31:0]   _zz_mySIntWord_4;
wire                myBool;
wire       [7:0]    mySInt_1;
wire       [127:0]  mySInt_128bits;
wire       [16:0]   mySInt;
wire       [16:0]   myBits;
wire       [1:0]    sel;
wire       [31:0]   mySIntWord;
wire       [31:0]   myUInt_32bits;
wire       [7:0]    myUInt_8bits;
wire       [7:0]    myUInt;
wire       [16:0]   mySInt_abs;

assign _zz_mySInt = {mySInt_1,mySInt_1};
assign _zz_mySIntWord_1 = mySInt_128bits[31 : 0];
assign _zz_mySIntWord_2 = mySInt_128bits[63 : 32];
assign _zz_mySIntWord_3 = mySInt_128bits[95 : 64];
assign _zz_mySIntWord_4 = mySInt_128bits[127 : 96];
always @(*) begin
    case(sel)
        2'b00 : _zz_mySIntWord = _zz_mySIntWord_1;
        2'b01 : _zz_mySIntWord = _zz_mySIntWord_2;
        2'b10 : _zz_mySIntWord = _zz_mySIntWord_3;
        default : _zz_mySIntWord = _zz_mySIntWord_4;
    endcase
end

assign myBool = mySInt[0];
assign mySInt = {_zz_mySInt,myBool};
assign myBits = {{mySInt_1,mySInt_1},myBool};
assign mySIntWord = _zz_mySIntWord;
assign myUInt_32bits = 32'h11223344;
assign myUInt_8bits = myUInt_32bits[7:0];
assign myUInt = 8'h28;
assign mySInt_abs = 17'h0;

assign _zz_mySInt = ({myBool,(myBool ? (~ myUInt) : myUInt)} + _zz_mySInt_1);
assign _zz_mySInt_2 = myBool;
assign _zz_mySInt_1 = {8'd0, _zz_mySInt_2};

assign _zz_mySInt_abs = (mySInt[8] ? _zz_mySInt_abs_1 : mySInt);
assign _zz_mySInt_abs_1 = (~ mySInt);
assign _zz_mySInt_abs_3 = mySInt[8];
assign _zz_mySInt_abs_2 = {8'd0, _zz_mySInt_abs_3};

assign mySInt_abs = (_zz_mySInt_abs + _zz_mySInt_abs_2);

四、定点数操作(FixPoint operations)

对于定点数, 我们可以把它分成两个部分:

  • 低位操作(四舍五入)

  • 高位操作(饱和运算)

  1. 低位操作(Lower bit operations)

    lowerBitOperation

SpinalHDL舍入类型 Wikipedia舍入类型 API 数学算法 返回(align=false) 支持程度
FLOOR RoundDown floor floor(x) w(x)-n bits Yes
FLOORTOZERO RoundToZero floorToZero sign*floor(abs(x)) w(x)-n bits Yes
CEIL RoundUp ceil ceil(x) w(x)-n+1 bits Yes
CEILTOINF RoundToInf ceilToInf sign*ceil(abs(x)) w(x)-n+1 bits Yes
ROUNDUP RoundHalfUp roundUp floor(x+0.5) w(x)-n+1 bits Yes
ROUNDDOWN RoundHalfDown roundDown ceil(x-0.5) w(x)-n+1 bits Yes
ROUNDTOZERO RoundHalfToZero roundToZero sign*ceil(abs(x)-0.5) w(x)-n+1 bits Yes
ROUNDTOINF RoundHalfToInf roundToInf sign*floor(abs(x)+0.5) w(x)-n+1 bits Yes
ROUNDTOEVEN RoundHalfToEven roundToEven
ROUNDTOODD RoundHalfToOdd roundToOdd

备注:RoundToEven和RoundToOdd模式都非常特殊, 常用在高精度大数据统计领域, SpinalHDL还没有支持它们。

你会发现ROUNDUP, ROUNDDOWN, ROUNDTOZERO, ROUNDTOINF, ROUNDTOEVEN, ROUNDTOODD在行为上非常相似, ROUNDTOINF所最常见的, 不同编程语言中的四舍五入方法可能不同。

| 编程语言 | 默认四舍五入类型 | 举例 | 评估 | | :——–: | :————–: | :———————————————————-: | :—————–: | | | Matlab | ROUNDTOINF | round(1.5)=2, round(2.5)=3
round(-1.5)=-2, round(-2.5)=-3 | round to +-Infinity | | python2 | ROUNDTOINF | round(1.5)=2, round(2.5)=3
round(-1.5)=-2, round(-2.5)=-3 | round to +-Infinity | | python3 | ROUNDTOEVEN | round(1.5)=round(2.5)=2
round(-1.5)=round(-2.5)=-2 | close to Even | | Scala.math | ROUNDTOUP | round(1.5)=2, round(2.5)=3
round(-1.5)=-1, round(-2.5)=-2 | always to +Infinity | | SpinalHDL | ROUNDTOINF | round(1.5)=2, round(2.5)=3
round(-1.5)=-2, round(-2.5)=-3 | round to +-Infinity |

备注:在SpinalHDL中ROUNDTOINF默认是RoundType(round = roundToInf)

val A = SInt(16 bits)
val B = A.roundToInf(6)    //默认'align=false', 会得到11 bits
val B = A.roundToInf(6, align = true)  //舍去进位, 得到10 bits
val B = A.floor(6 bits)         //返回10 bits
val B = A.floorToZero(6 bits)   //返回10 bits
val B = A.ceil(6 bits)          //带进位故返回11 bits
val B = A.ceil(6 bits, align = true)    //舍去进位, 得到10 bits
val B = A.ceilToInf(6 bits)
val B = A.roundUp(6 bits)
val B = A.roundDown(6 bits)
val B = A.roundToInf(6 bits)
val B = A.roundToZero(6 bits)
val B = A.round(6 bits)         //SpinalHDL用roundToInf作为默认rounding模式

val B0 = A.roundToInf(6 bits, align = true) //---+
                                            //--> equal
val B1 = A.roundToInf(6 bits, align = false).sat(1) //---+

Verilog:

//这里只举一个例子,其他的可自行生成
//val B = A.roundToInf(6, align = true)     当前版本默认align = true,与文档有所不同    有符号数两边近似
wire       [16:0]   _zz__zz_when_SInt_l337_2;
wire       [16:0]   _zz__zz_when_SInt_l337_2_1;
wire       [5:0]    _zz_when_SInt_l191;
wire       [10:0]   _zz__zz_B_3;
wire       [10:0]   _zz__zz_B_3_1;
wire       [16:0]   _zz__zz_B;
wire       [16:0]   _zz__zz_B_1;
wire       [16:0]   _zz__zz_B_2;
wire       [1:0]    _zz_when_SInt_l131;
wire       [0:0]    _zz_when_SInt_l137;
wire       [15:0]   A;
reg        [10:0]   _zz_B;
wire       [15:0]   _zz_B_1;
wire       [15:0]   _zz_when_SInt_l337;
wire       [15:0]   _zz_when_SInt_l337_1;
wire       [16:0]   _zz_when_SInt_l337_2;
wire       [15:0]   _zz_B_2;
wire                when_SInt_l337;
reg        [10:0]   _zz_B_3;
wire                when_SInt_l191;
reg        [9:0]    B;
wire                when_SInt_l130;
wire                when_SInt_l131;
wire                when_SInt_l137;
reg        [7:0]    counter;

assign _zz__zz_when_SInt_l337_2 = {_zz_when_SInt_l337_1[15],_zz_when_SInt_l337_1};  //A符号位拓展1bit
assign _zz__zz_when_SInt_l337_2_1 = {_zz_when_SInt_l337[15],_zz_when_SInt_l337};    //前6bit为0,其余为1的符号位拓展, 即-2^5
assign _zz_when_SInt_l191 = _zz_when_SInt_l337_2[5 : 0];                            //A-0.5的小数部分
assign _zz__zz_B_3 = _zz_when_SInt_l337_2[16 : 6];                                  //A-0.5的整数部分
assign _zz__zz_B_3_1 = 11'h001;                                                     //1
assign _zz__zz_B = ($signed(_zz__zz_B_1) + $signed(_zz__zz_B_2));                   //符号位拓展后的A+2^5, 相当于A+0.5
assign _zz__zz_B_1 = {_zz_B_2[15],_zz_B_2};                                         //A符号位拓展1bit
assign _zz__zz_B_2 = {_zz_B_1[15],_zz_B_1};                                         //2^5符号位拓展1bit
assign _zz_when_SInt_l131 = _zz_B[10 : 9];                                          //溢出判断位
assign _zz_when_SInt_l137 = _zz_B[9 : 9];                                           //符号位
assign _zz_B_1 = {{10'h0,1'b1},5'h0};                                               //16‘b0000_0000_0010_0000, 即2^5
assign _zz_when_SInt_l337 = {11'h7ff,5'h0};                                         //前5bit为0,其余为1. 即-2^5
assign _zz_when_SInt_l337_1 = A[15 : 0];
assign _zz_when_SInt_l337_2 = ($signed(_zz__zz_when_SInt_l337_2) + $signed(_zz__zz_when_SInt_l337_2_1));    //符号位拓展后的A-2^5, 相当于A-0.5
assign _zz_B_2 = A[15 : 0];                                                         //A
assign when_SInt_l337 = _zz_when_SInt_l337_2[16];                                   //A-0.5符号位
assign when_SInt_l191 = (|_zz_when_SInt_l191);                                      //A-0.5小数部分是否为0
always @(*) begin
    if(when_SInt_l191) begin
        _zz_B_3 = ($signed(_zz__zz_B_3) + $signed(_zz__zz_B_3_1));                  //非0的话A-0.5的整数部分+1
    end else begin
        _zz_B_3 = _zz_when_SInt_l337_2[16 : 6];                                     //0的话结果为 A-0.5 整数部分
    end
end

always @(*) begin
    if(when_SInt_l337) begin                                                        //负数时取
        _zz_B = _zz_B_3;
    end else begin
        _zz_B = (_zz__zz_B >>> 6);                                                  //非负时A+0.5整数部分
    end
end

assign when_SInt_l130 = _zz_B[10];
assign when_SInt_l131 = (! (&_zz_when_SInt_l131));
always @(*) begin
    if(when_SInt_l130) begin
        if(when_SInt_l131) begin
            B = 10'h200;
        end else begin
            B = _zz_B[9 : 0];
        end
    end else begin
        if(when_SInt_l137) begin
            B = 10'h1ff;
        end else begin
            B = _zz_B[9 : 0];
        end
    end
end

assign when_SInt_l137 = (|_zz_when_SInt_l137);

备注:只有floorfloorToZero没有align选项, 它们不需要进位bit(align=true)。其他近似算法都默认带进位信息。

API UInt/SInt 描述 Return(align=false) Return(align=true)
floor Both w(x)-n bits w(x)-n bits
floorToZero SInt 与无符号floor相等 w(x)-n bits w(x)-n bits
ceil Both w(x)-n+1 bits w(x)-n bits
ceilToInf SInt 与无符号ceil相等 w(x)-n+1 bits w(x)-n bits
roundUp Both 仅为了HW w(x)-n+1 bits w(x)-n bits
roundDown Both w(x)-n+1 bits w(x)-n bits
roundToInf SInt 最常用 w(x)-n+1 bits w(x)-n bits
roundToZero SInt 无符号时等于roundDown w(x)-n+1 bits w(x)-n bits
round Both 在SpinalHDL中默认roundToInf w(x)-n+1 bits w(x)-n bits

备注:尽管roundToInf很常用, roundUp有着最小的开销和最好的时序, 并且几乎没有性能损失。因此强烈推荐使用roundUp

  1. 高位操作(High bit operations)

    highBitOperation

函数 操作 正数操作 负数操作
sat 饱和 when(Top[w-1, w-n].orR)set maxValue when(Top[w-1, w-n].andR)set minValue
trim 舍弃 N/A N/A
symmetry 对称 N/A minValue=-maxValue

对称仅对SInt有效

val A = SInt(8 bits)
val B = A.sat(3 bits)       //高3 bits饱和的5 bits返回值
val B = A.sat(3)            //与上式同理
val B = A.trim(3 bits)      //高3 bits舍弃的5bits返回值
val C = A.symmetry          //像(-128~127 to -127~127)一样返回8 bits
val C = A.sat(3).symmetry          //像(-16~15 to -15~15)一样返回5 bits

Verilog:

//饱和
wire       [3:0]    _zz_when_SInt_l131;
wire       [2:0]    _zz_when_SInt_l137;
wire       [7:0]    A;
reg        [4:0]    B;
wire                when_SInt_l130;
wire                when_SInt_l131;
wire                when_SInt_l137;

assign _zz_when_SInt_l131 = A[7 : 4];
assign _zz_when_SInt_l137 = A[6 : 4];
assign when_SInt_l130 = A[7];
assign when_SInt_l131 = (! (&_zz_when_SInt_l131));
always @(*) begin
    if(when_SInt_l130) begin
        if(when_SInt_l131) begin
            B = 5'h10;
        end else begin
            B = A[4 : 0];
        end
    end else begin
        if(when_SInt_l137) begin
            B = 5'h0f;
        end else begin
            B = A[4 : 0];
        end
    end
end

assign when_SInt_l137 = (|_zz_when_SInt_l137);

//trim舍弃
wire       [7:0]    A;
wire       [4:0]    B;

assign B = A[4 : 0];

//对称
wire       [7:0]    _zz_B;
wire       [7:0]    _zz_B_1;
wire       [7:0]    A;
wire       [7:0]    B;

assign _zz_B = 8'h80;
assign _zz_B_1 = 8'h81;
assign B = (($signed(A) == $signed(_zz_B)) ? _zz_B_1 : A);
  1. fixTo函数(fixTo function)

    针对UInt/SInt提供了两种定点方法:

    fixPoint

    强烈推荐在RTL工程中使用fixTo, 有了这个函数你就不需要处理进位alignment和bit宽度的计算问题, 如同上图Way1那样。

    Fix函数关于自动处理饱和:

函数 描述 返回类型
fixTo(section, roundType, symmetric) Factory FixFunction section.size bits
val A = SInt(16 bits)
val B = A.fixTo(10 downto 3) //默认的RoundType是ROUNDTOINF, sym=false
val B = A.fixTo(8 downto 0, RoundType.ROUNDUP)
val B = A.fixTo(9 downto 3, RoundType.CEIL, sym = false)
val B = A.fixTo(16 downto 1, RoundType.ROUNDTOINF, sym = true)
val B = A.fixTo(10 downto 3, RoundType.FLOOR)   //向下取整3 bits, 舍弃进位5 bits @ highest
val B = A.fixTo(20 downto 3, RoundType.FLOOR)   //向下取整3 bits,拓展进位2 bits @ highest

Verilog:

wire       [7:0]    fixTo_dout;
wire       [15:0]   A;

SInt16fixTo10_3_ROUNDTOINF fixTo (
    .din  (A[15:0]        ), //i
    .dout (fixTo_dout[7:0])  //o
);

module SInt16fixTo10_3_ROUNDTOINF (
  input      [15:0]   din,
  output     [7:0]    dout
);

  wire       [16:0]   _zz__zz_dout_4;
  wire       [16:0]   _zz__zz_dout_4_1;
  wire       [2:0]    _zz_when_SInt_l191;
  wire       [13:0]   _zz__zz_dout_6;
  wire       [13:0]   _zz__zz_dout_6_1;
  wire       [16:0]   _zz__zz_dout;
  wire       [16:0]   _zz__zz_dout_1;
  wire       [16:0]   _zz__zz_dout_2;
  wire       [6:0]    _zz_when_SInt_l131;
  wire       [5:0]    _zz_when_SInt_l137;
  reg        [13:0]   _zz_dout;
  wire       [15:0]   _zz_dout_1;
  wire       [15:0]   _zz_dout_2;
  wire       [15:0]   _zz_dout_3;
  wire       [16:0]   _zz_dout_4;
  wire       [15:0]   _zz_dout_5;
  wire                when_SInt_l337;
  reg        [13:0]   _zz_dout_6;
  wire                when_SInt_l191;
  reg        [7:0]    _zz_dout_7;
  wire                when_SInt_l130;
  wire                when_SInt_l131;
  wire                when_SInt_l137;

assign _zz__zz_dout_4 = {_zz_dout_3[15],_zz_dout_3};
assign _zz__zz_dout_4_1 = {_zz_dout_2[15],_zz_dout_2};
assign _zz_when_SInt_l191 = _zz_dout_4[2 : 0];
assign _zz__zz_dout_6 = _zz_dout_4[16 : 3];
assign _zz__zz_dout_6_1 = 14'h0001;
assign _zz__zz_dout = ($signed(_zz__zz_dout_1) + $signed(_zz__zz_dout_2));
assign _zz__zz_dout_1 = {_zz_dout_5[15],_zz_dout_5};
assign _zz__zz_dout_2 = {_zz_dout_1[15],_zz_dout_1};
assign _zz_when_SInt_l131 = _zz_dout[13 : 7];
assign _zz_when_SInt_l137 = _zz_dout[12 : 7];
assign _zz_dout_1 = {{13'h0,1'b1},2'b00};
assign _zz_dout_2 = {14'h3fff,2'b00};
assign _zz_dout_3 = din[15 : 0];
assign _zz_dout_4 = ($signed(_zz__zz_dout_4) + $signed(_zz__zz_dout_4_1));
assign _zz_dout_5 = din[15 : 0];
assign when_SInt_l337 = _zz_dout_4[16];
assign when_SInt_l191 = (|_zz_when_SInt_l191);
always @(*) begin
    if(when_SInt_l191) begin
        _zz_dout_6 = ($signed(_zz__zz_dout_6) + $signed(_zz__zz_dout_6_1));
    end else begin
        _zz_dout_6 = _zz_dout_4[16 : 3];
    end
end

always @(*) begin
    if(when_SInt_l337) begin
        _zz_dout = _zz_dout_6;
    end else begin
        _zz_dout = (_zz__zz_dout >>> 3);
    end
end

assign when_SInt_l130 = _zz_dout[13];
assign when_SInt_l131 = (! (&_zz_when_SInt_l131));
always @(*) begin
    if(when_SInt_l130) begin
        if(when_SInt_l131) begin
            _zz_dout_7 = 8'h80;
        end else begin
            _zz_dout_7 = _zz_dout[7 : 0];
        end
    end else begin
        if(when_SInt_l137) begin
            _zz_dout_7 = 8'h7f;
        end else begin
            _zz_dout_7 = _zz_dout[7 : 0];
        end
    end
end

assign when_SInt_l137 = (|_zz_when_SInt_l137);
assign dout = _zz_dout_7;