饱和计数器
从功能上讲,就是普通的饱和计数器(加到最大值后继续加仍然保持最大值,减到最小值后继续减仍然保持最小值),但是使用了非常面向对象的实现方法来简化使用。
有符号和无符号饱和计数器的实现是相似的,下面以无符号版本进行说明。
class SaturateCounter
饱和计数器类实现,提供各种类方法。
- 比较
- 重载了常见比较运算符(
===、=/=、<、>、<=、>=),和普通的 UInt 比较方法一致
- 重载了常见比较运算符(
- 获取状态
- 饱和程度
- 饱和:
.isSaturate() - 临界(再加减 1 就会切换方向):
.isWeak() - 非饱和非临界:
.isMid()
- 饱和:
- 方向:
- 正向:
.isPositive() - 负向:
.isNegative()
- 正向:
- 以及它们的组合,如是否为正向饱和:
.isSaturatePositive()
- 饱和程度
- 获取更新后的饱和计数器(返回更新后的新实例,可用于 wire)
- 更新±1:
.getUpdate(increase, en),若en为 False 则不更新,否则,若increase为 True 则加 1,否则减 1。 - 正向更新:
.getIncrease(step, en),当step为 1 时等价于.getUpdate(True, en),step可以大于 1 来一次性增加多个级别的饱和程度,但需要注意会在选择端引入额外的width+1bit 位宽的比较器。 - 负向更新:
.getDecrease(step, en),类似
- 更新±1:
- 自更新(在当前实例上更新,仅可用于 reg,无返回值)
- 更新±1:
.selfUpdate(increase, en),类似于.getUpdate(increase, en) - 正/负向更新:
.selfIncrease(step, en)和.selfDecrease(step, en),同理
- 更新±1:
- 复位(在当前实例上更新,仅可用于 reg,无返回值)
- 归零:
.resetZero() - 复位正向饱和:
.resetSaturatePositive() - 复位正向临界:
.resetWeakPositive() - 复位负向同理
- 需要注意的是,对无符号饱和计数器来讲,
.resetZero()和.resetSaturateNegative()是等价的;而对有符号的饱和计数器来讲,.resetZero()和.resetWeakPositive()是等价的。由于这点模糊性,不建议使用.resetZero()来复位饱和计数器。
- 归零:
object SaturateCounter
计算给定位宽的饱和计数器的饱和/临界常量值,返回 Int 或饱和计数器实例。
- 获取 Int:
SaturateCounter.Value.AAABBB(width) - 获取饱和计数器实例:
SaturateCounter.AAABBB(width)
其中 AAA 为饱和程度(Saturate,Weak),BBB 为方向(Positive、Negative),和类方法的 isAAABBB() 依次对应
object SaturateCounterInit
快速实例化一个饱和计数器并为其赋值。
val counter = SaturateCounterInit(width, value)
// 等价于
val counter = new SaturateCounter(width)
counter.value := value // 如果 value 是 Int,或者
counter.value := value.U // 如果 value 是 UInt
trait SaturateCounterFactory
针对 XiangShan 的参数传递体系设计的工厂方法,用于快速创建特定名字的饱和计数器 object,从而简化 width 的传递,减少多个不同位宽的饱和计数器之间容易笔误的问题。
可以创建 object XxxCounter extends SaturateCounterFactory,并在其中定义 def width(implicit p: Parameters): Int 来指定位宽,然后在代码中直接使用 XxxCounter() 来实例化对应位宽的饱和计数器,以及使用 XxxCounter.AAABBB 来获取对应的常量值。
object TageTakenCounter extends SaturateCounterFactory {
def width(implicit p: Parameters): Int = p(XSCoreParamsKey).frontendParameters.bpuParameters.tageParameters.TakenCntWidth
}
class TageIO(implicit p: Parameters) extends Bundle {
val takenCnt = Output(TageTakenCounter())
}
class Tage(implicit p: Parameters) extends Module {
val takenCnt = TageTakenCounter()
takenCnt := Mux(
needReset,
if (resetPositive) TageTakenCounter.WeakPositive else TageTakenCounter.WeakNegative,
takenCnt.getUpdate(increase, en)
)
}
// 等价于
// 每次实例化 taken counter / 使用常量都要手动传递 width
trait TageParameters {
implicit val p: Parameters
def TakenCntWidth: Int = p(XSCoreParamsKey).frontendParameters.bpuParameters.tageParameters.TakenCntWidth
}
class TageIO(implicit p: Parameters) extends Bundle with TageParameters {
val takenCnt = Output(new SaturateCounter(TakenCntWidth))
}
class Tage(implicit p: Parameters) extends Module with TageParameters {
val takenCnt = new SaturateCounter(TakenCntWidth)
takenCnt := Mux(
needReset,
if (resetPositive) SaturateCounter.WeakPositive(TakenCntWidth) else SaturateCounter.WeakNegative(TakenCntWidth),
takenCnt.getUpdate(increase, en)
)
}