【SpinalHDL快速入门】4.3、基本类型之UInt/SInt

文章目录

    • 1.1、描述
    • 1.2、声明
    • 1.3、运算符
      • 1.3.1、逻辑运算(Logic)
      • 1.3.2、算术运算(Arithmetic)
      • 1.3.3、比较(Comparison)
      • 1.3.4、类型转换(Type Cast)
      • 1.3.5、部分赋值/提取操作符(Bit extraction)
      • 1.3.6、杂项(Misc)
    • 1.4、固定点运算(FixPoint operations)【了解】
      • 1.4.1、低位操作(Lower bit operations)
      • 1.4.2、高位操作(High bit operations )
      • 1.4.3、fixTo function

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第1张图片

1.1、描述

UInt/SInt类型对应于一组bits,可用于有符号/无符号整数运算。

1.2、声明

声明整数的语法如下:([] 中的所有内容都是可选项)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第2张图片

val myUInt = UInt(8 bits)
myUInt := U(2,8 bits)
myUInt := U(2)
myUInt := U"0000_0101" // Base per default is binary => 5
myUInt := U"h1A" 	// Base could be x (base 16)
					// h (base 16)
					// d (base 10)
					// o (base 8)
					// b (base 2)
myUInt := U"8’h1A"
myUInt := 2 // You can use a Scala Int as a literal value【注意,直接写数字默认是Int】

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

// For assignment purposes, you can omit the U/S, which also allows the use of the [default -> ???] feature
myUInt := (default -> true) // Assign myUInt with "11111111"
myUInt := (myUInt.range -> true) // Assign myUInt with "11111111"
myUInt := (7 -> true, default -> false) // Assign myUInt with "10000000"
myUInt := ((4 downto 1) -> true, default -> false) // Assign myUInt with "00011110"

1.3、运算符

UInt和SInt类型支持以下运算符:

1.3.1、逻辑运算(Logic)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第3张图片

注意:x rotateLeft yx rotateRight y 也是有效的语法。

注意:请注意 x >> 2:T(w(x)-2)x >> U(2):T(w(x)) 之间的区别。两者的不同在于,在第一种情况下,数字 2 是一个 Int(可以看作是“elaboration integer”),而在第二种情况下它是一个硬件信号。【类比上一节中的 >> y的类型】

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

// Bitwise operators
c := ~(a & b) // Inverse(a AND b)
assert(c.getWidth == 32)

// Shift
val arithShift = UInt(8 bits) << 2 // shift left (resulting in 10 bits)
val logicShift = UInt(8 bits) |<< 2 // shift left (resulting in 8 bits)
assert(arithShift.getWidth == 10)
assert(logicShift.getWidth == 8)

// Rotation
val rotated = UInt(8 bits) rotateLeft 3 // left bit rotation
assert(rotated.getWidth == 8)

// Set all bits of b to True when all bits of a are True
when(a.andR) { b.setAll() }

注意:对于SInt左移操作,其提供的算数左移操作将会进行位宽扩展,若想位宽保持不变,可以进行位宽截取(SpinalHDL里提供了非常方便的位宽截取处理方式)。而逻辑左移操作的处理方式与UInt无二差别。

1.3.2、算术运算(Arithmetic)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第4张图片

针对加法和减法,SpinalHDL均提供了三种方式实现:

  • x+y、x-y: 与Verilog中的加减操作符相同,对于溢出不做处理。
  • x+^y、x-^y: 为了防止加减法溢出,该方法提供了带位宽扩展的操作处理
  • x+|y、x-|y:该操作符对于溢出场景,做截断饱和处理
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")

注意:请注意这里如何进行仿真断言(simulation assertions)(使用===),而不是前面示例中的elaboration assertions(使用==)。

1.3.3、比较(Comparison)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第5张图片

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()
}

注意:当以允许“环绕(wraparound)”行为的方式比较UInt值时,意味着当它们超过最大值时,这些值将“环绕”到最小值。可以使用UInt的wrap方法作为x.wrap < y来处理UInt变量x、y,如果在环绕意义下x小于y,则结果为true。【不是太懂????】

1.3.4、类型转换(Type Cast)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第6张图片
将 Bool、Bits 或 SInt 转换为 UInt,可以使用 U(something)。要将东西转换为 SInt,可以使用 S(something)。

// Cast an SInt to Bits
val myBits = mySInt.asBits

// Create a Vector of Bool
val myVec = myUInt.asBools

// Cast a Bits to SInt
val mySInt = S(myBits)

1.3.5、部分赋值/提取操作符(Bit extraction)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第7张图片

// get the bit at index 4
val myBool = myUInt(4)

// assign bit 1 to True
mySInt(1) := True

// Range
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

1.3.6、杂项(Misc)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第8张图片

  • ##@@操作符均为拼接操作符,两者差别在于返回结果类型不同##返回类型为Bits,而@@返回类型为x变量类型
  • twoCompelment可将UInt通过二进制补码转换为SInt(en为True)。
  • expand对于SInt而言会扩展符号位
myBool := mySInt.lsb // equivalent to mySInt(0)

// Concatenation
val mySInt = mySInt_1 @@ mySInt_1 @@ myBool
val myBits = mySInt_1 ## mySInt_1 ## myBool

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

// If you want to access in reverse order you can do:【这个实例跟前面的类似!!!】
val myVector = mySInt_128bits.subdivideIn(32 bits).reverse
val mySIntWord = myVector(sel)

// Resize
myUInt_32bits := U"32’x112233344"
myUInt_8bits := myUInt_32bits.resized // automatic resize (myUInt_8bits = 0x44)
val lowest_8bits = myUInt_32bits.resize(8) // resize to 8 bits (myUInt_8bits = 0x44)

// Two's complement
mySInt := myUInt.twoComplement(myBool)

// Absolute value
mySInt_abs := mySInt.abs

1.4、固定点运算(FixPoint operations)【了解】

对于定点数,我们可以将其分为两部分:

  • 低位操作(舍入方法)Lower bit operations (rounding methods)
  • 高位操作(饱和运算)High bit operations (saturation operations)

1.4.1、低位操作(Lower bit operations)

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第9张图片

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第10张图片

注意:RoundToEvenRoundToOdd模式非常特殊,用于一些高精度的大数据统计领域。目前SpinalHDL还不支持这两种模式。

你会发现ROUNDUP,ROUNDDOWN,ROUNDTOZERO,ROUNDTOINF,ROUNDTOEVEN和ROUNTOODD的行为非常相似,其中ROUNDTOINF是最常见的。不同编程语言中舍入的行为可能有所不同。

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第11张图片

注意:在SpinalHDL中,ROUNDTOINF是默认的RoundType(round = roundToInf)

val A = SInt(16 bits)
val B = A.roundToInf(6 bits) //默认使用带进位的“align = false”,得到了11位 = 16-6+1
val B = A.roundToInf(6 bits, align = true) // sat 1 carry bit, got 10 bit = 16-6
val B = A.floor(6 bits) // return 10 bit
val B = A.floorToZero(6 bits) // return 10 bit
val B = A.ceil(6 bits) // ceil with carry so return 11 bit
val B = A.ceil(6 bits, align = true) // ceil with carry then sat 1 bit return 10 bit
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 uses roundToInf as the default rounding mode
val B0 = A.roundToInf(6 bits, align = true) // ---+
											// |--> equal
val B1 = A.roundToInf(6 bits, align = false).sat(1) // ---+

注意:仅 floor 和 floorToZero 可以在不使用 align 选项的情况下工作;它们不需要进位比特。其他舍入操作默认使用进位比特

1.4.2、高位操作(High bit operations )

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第12张图片
【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第13张图片
对于SInt,Symmetric是唯一有效的。

val A = SInt(8 bits)
val B = A.sat(3 bits) // return 5 bits with saturated highest 3 bits
val B = A.sat(3) // equal to sat(3 bits)
val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val C = A.symmetry // return 8 bits and symmetry as (-128~127 to -127~127)
val C = A.sat(3).symmetry // return 5 bits and symmetry as (-16~15 to -15~15)

1.4.3、fixTo function

在UInt/SInt中提供了两种方法来进行定点数:

【SpinalHDL快速入门】4.3、基本类型之UInt/SInt_第14张图片
在RTL工作中强烈推荐使用 fixTo,无需像上图中的Way1那样手动处理进位比特对齐和比特宽度计算

具有自动饱和功能的Factory Fix函数:

在这里插入图片描述

val A = SInt(16 bits)
val B = A.fixTo(10 downto 3) // default 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) // floor 3 bit, sat 5 bit @ highest
val B = A.fixTo(20 downto 3, RoundType.FLOOR) // floor 3 bit, expand 2 bit @ highest

你可能感兴趣的:(SpinalHDL快速入门,scala,SpinalHDL,数字IC)