工具(Utils)

一、 总览

句式 返回
类型
描述
widthOf(x : BitVector) Int 返回一个类型为Bits/UInt/SInt的信号的位宽
log2Up(x : BigInt) Int 返回表示输入状态x所需要的位数
isPow2(x : BigInt) Boolean x为2的指数时, 返回True
roundUp(
that : BigInt,
by : BigInt)
BigInt 返回参数by乘参数that的结果
Cat(x : Data*) Bits 连接所有的参数, 其中第一个参数会放置在最高有效位(MSB), 最后一个参数放置在最低有效位(LSB)

二、克隆硬件数据类型(Cloning hardware datatypes)

用户可以通过cloneOf(x)函数克隆给定的硬件数据类型。该函数将会返回一个拥有相同Scala类型和参数的新实例。例如:

def plusOne(value : UInt) : UInt = {
    // 将会生成一个和`value`同位宽的UInt类型
    val temp = cloneOf(value)
    temp := value + 1
    return temp
}

// treePlusOne 将会成为一个8比特的值
val treePlusOne = plusOne(U(3, 8 bits))

注意!:若对一个Bundle类型使用cloneOf(x)函数功能, 需要确保该Bundle是一个case类, 否则需要在Bundle内部重写克隆函数。

三、传递数据类型作为结构参数(Passing a datatype as construction parameter)

许多可重用的硬件要求能够被一些数据类型所参数化。例如如果用户想要定义一个FIFO或者移位寄存器, 则需要一个参数来定义该硬件所需的负载。

  1. 传统方式

    以定义一个ShiftRegister元件为例, 介绍传统的传递数据类型方式如下:

    case class ShiftRegister[T <: Data](dataType: T, depth: Int) extends Component {
        val io = new Bundle {
        val input  = in (cloneOf(dataType))
        val output = out(cloneOf(dataType))
        //需要在Case Class内部重写`cloneof`函数
        }
    }
    

    实例化该元件的代码为:

    val shiftReg = ShiftRegister(Bits(32 bits), depth = 8)
    

    在上述例子中, 硬件的数据类型(位宽)直接作为构造参数传递。因此每次需要例化或是用该datatype时, 都需要使用cloneOf函数对其datatype进行定义。这种方式并不安全因为常cloneOf函数会被遗忘。

  2. 更安全的方式

    以更安全的方式来传递数据类型的例子如下:

    case class ShiftRegister[T <: Data](dataType: HardType[T], depth: Int) extends Component {
        val io = new Bundle {
        val input  = in (dataType())
        val output = out(dataType())
        }
    }
    

    实例化该元件的代码为:

    val shiftReg = ShiftRegister(Bits(32 bits), depth = 8)
    

    在上述的更安全的方法中, 使用了HardType去封装数据类型T, 可以看成是T的蓝图(blueprint)。这种方式相比于传统方式更加简单, 因为每次例化使用该datatype时, 只需要调用HardTypeapply函数即可。此外, 从用户的角度来看, 这种机制是完全透明的, 因为硬件数据类型可以隐式转换为HardType

四、频率与时间(Frequency and time)

SpinalHDL有专门的语法来定义频率和时间值:

val frequency = 100 MHz
val timeoutLimit = 3 ms
val period = 100 us

val periodCycles = frequency * period
val timeoutCycles = frequency * timeoutLimit

对一个时间定义, 可以利用如下后缀得到一个TimeNumber: fs, ps, ns, us, ms, sec, mn, hr; 可以利用如下后缀得到一个HertzNumber: Hz, KHz, MHz, GHz, THz

TimeNumberHertzNumber是基于PhysicalNumber类, 该类在Scala中利用BigDecimal存储数据。

五、二进制前缀(Binary prefix)

SpinalHDL允许根据IEC, 来使用二进制前缀表示法定义整数。

val memSize = 512 MiB
val dpRamSize = 4 KiB

可使用的所有二进制前缀如下:

二进制前缀 表示值
Byte, Bytes 1
KiB 1024 == 1 << 10
MiB 10242 == 1 << 20
GiB 10243 == 1 << 30
TiB 10244 == 1 << 40
PiB 10245 == 1 << 50
EiB 10246 == 1 << 60
ZiB 10247 == 1 << 70
YiB 10248 == 1 << 80