## Utils(实用工具)
有一些实用工具已在Spinal.core(请见**其他语言特征**章节中的Utils部分)。
### 一、State less utilities(免状态工具)
| 句式 | 返回类型 | 描述 |
| :-------------------------------------------------------------------------: | :------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| `toGray(x : UInt)` | Bits | 返回X的格雷码 |
| `fromGray(x : Bits)` | UInt | 返回格雷码X转换后的UInt值 |
| `Reverse(x : T)` | T | 翻转所有比特 (lsb + n -> msb - n) |
| `OHToUInt(x : Seq[Bool])`
`OHToUInt(x : BitVector)` | UInt | 返回独热编码`x`中1的坐标 |
| `CountOne(x : Seq[Bool])`
`CountOne(x : BitVector)` | UInt | 返回`x`中1的个数 |
| `MajorityVote(x : Seq[Bool])`
`MajorityVote(x : BitVector)` | Bool | 当1的数量>(x.size/2)时, 返回true |
| `EndiannessSwap(that: T[, base:BitCount])` | T | Big-Endian <-> Little-Endian 大头端与小头端互换 |
| `OHMasking.first(x : Bits)` | Bits | 保持x中的第一个比特1不变 |
| `OHMasking.last(x : Bits)` | Bits | 保持x中的最后一个比特1不变 |
| `OHMasking.roundRobin(`
`requests : Bits,`
`ohPriority : Bits`
`)` | Bits | 根据`ohPriority`给出的优先级使得`requests`中的某个比特1保持不变。例如, 假设`requests`等于"1001", `ohPriority`等于"0010", 则`roundRobin`函数会根据`ohPriority`提供的优先级对`requests`进行轮询仲裁, 并且返回"1000" |
| `MuxOH (`
`oneHot : IndexedSeq[Bool],`
`inputs : Iterable[T]`
`)` | T | 根据`oneHot`向量提供的信息, 对输入`inputs`进行选通并返回选通后的`T` |
| `PriorityMux (`
`sel: Seq[Bool],`
`in: Seq[T]`
`)` | T | 返回`in`中第一个对应`sel`位为`True`的元素 |
| `PriorityMux (`
`in: Seq[(Bool, T)]`
`)` | T | 返回`in`中第一个对应`sel`位为`True`的元素 |
### 二、State full utilities(全状态工具)
| 句式 | 返回类型 | 描述 |
| :-------------------------------------------: | :------: | :----------------------------------------------------------------------------------------------------------------------------------: |
| `Delay(that: T, cycleCount: Int)` | T | 延迟`cycleCount`个周期后返回`that` |
| `History(that: T, length: Int[,when : Bool])` | List[T] | 返回一个长度为`length`的向量。其中第一个元素是`that`, 最后一个是延迟(`length`-1)后的`that`。内部的移位寄存器会在`when`有效时进行采样 |
| `BufferCC(input : T)` | T | 返回利用两个触发器同步到当前时钟域的同步输入信号 |
1. 计数器
Counter工具可以用来实例化一个硬件计数器。
| 句式 | 描述 |
| :-------------------------------------------------: | :-------------------------------------: |
| `Counter(start: BigInt, end: BigInt[, inc : Bool])` | 无 |
| `Counter(range : Range[, inc : Bool])` | 与`x to y``x until y`语句匹配 |
| `Counter(stateCount: BigInt[, inc : Bool])` | 从0开始计数, 到`statecCount - 1`结束 |
| `Counter(bitCount: BitCount[, inc : Bool])` | 从0开始计数, 到`(1 << bitCoun) - 1`结束 |
一个计数器可以被方法所控制, 并且导线可以被读取:
```Scala
val counter = Counter(2 to 9) // 建立一个八状态计数器 (2 to 9)
// 方法
counter.clear() // 复位计数器
counter.increment() // 计数增加
// Wires
counter.value // 当前值
counter.valueNext // 下一个值
counter.willOverflow // 若当前循环计数器溢出, 则返回true
counter.willOverflowIfInc // 若当前循环增加一会导致计数器溢出, 则返回true
// Cast搜寻
when(counter === 5){ ... } // 计数器会隐式地投射搜寻到当前值
```
当一个是计数器溢出(达到最终值), 它会在下一个周期重启并设置为初始值。`CounterFreeRun`构建一个始终运行的计数器:`CounterFreeRun(stateCount: BigInt)`。
2. 超时(Timeout)
Timeout工具可以用来方便地例化一个硬件Timeout。
| 例化句式 | 描述 |
| :--------------------------------: | :-----------------------------: |
| `Timeout(cycles : BigInt)` | `cycles`个时钟后进行标记 |
| `Delay(that: T, cycleCount: Int)` | 持续`time`时间后进行标记 |
| `Timeout(frequency : HertzNumber)` | 以`frequency`的速率进行计时标记 |
下方代码举例了可以和Counter工具一起使用的不同语法句式的例子:
```Scala
val timeout = Timeout(10 ms) //计时10ms后的对象会被记为超时
when(timeout){ //检查是否被判断为超时
timeout.clear() //请求timeout工具清空他的标志位
}
```
> **备注:如果使用时间或频率设置实例化`Timeout`, 则隐含的`ClockDomain`应该具有频率设置。**
3. 复位控制(ResetControl)
复位控制提供了一些工具以管理复位。
- asyncAssertSyncDeassert
用户可以利用一个异步有效同步无效(asynchronously asserted synchronously de-asserted)逻辑来筛选异步复位。可以使用`ResetCtrl.asyncAssertSyncDeassert`函数来筛选并返回相应的值。
| 声明命名 | 返回类型 | 描述 |
| :------------: | :---------: | :----------------------------------------------------: |
| input | Bool | 筛选的信号 |
| clockDomain | ClockDomain | 返回将要使用所筛选值的时钟域 |
| inputPolarity | Polarity | HIGH/LOW (default=HIGH) |
| outputPolarity | Polarity | HIGH/LOW (default=clockDomain.config.resetActiveLevel) |
| bufferDepth | Int | 防止亚稳态所需的寄存器级数(默认为2) |
另外有一个ResetCtrl.asyncAssertSyncDeassertDrive版本的工具, 它直接分配clockDomain以重置的值。
### 三、特殊工具(Special utilities)
| 句式 | 返回类型 | 描述 |
| :------------------------------: | :------: | :--------------------------------------------------: |
| `LatencyAnalysis(paths : Node*)` | Int | 以周期为单位返回从第一个节点到最后一个节点的最短路径 |