【问题标题】:How to understand this line of chisel code怎么看懂这行凿码
【发布时间】:2019-11-11 17:55:34
【问题描述】:

我正在学习 chisel 和 scala 语言,并尝试分析一些火箭芯片代码行。有人能解释一下吗? https://github.com/chipsalliance/rocket-chip/blob/54237b5602a273378e3b35307bb47eb1e58cb9fb/src/main/scala/rocket/RocketCore.scala#L957

我了解 log2Up 函数在做什么,但不明白为什么 log2Up(n)-1 和 0 像“参数”一样传递给 UInt 类型的 val 的 addr!?

【问题讨论】:

  • 这就是您在 chisel 中执行位切片的方式。它调用 UInt 上的 apply 函数(带有两个整数参数的变体,即上限和下限),并且基本上会给您 addr 的 n 个最低有效位。
  • 另一个可能有用的提示是,由于寄存器 0 在 RISC-V ISA 中被硬编码为 0,Rocket 的寄存器文件使用了一个小技巧,与 RISC 相比,它在物理上颠倒了寄存器的顺序-V 规格。 x1rf 中的索引 31,而 x31 是索引 0。

标签: scala chisel rocket-chip


【解决方案1】:

我找不到UInt 的定义位置,但如果我不得不猜测,UInt 是一个class,它有一个apply 方法。这是一个特殊的方法,它允许我们在类的实例上使用括号运算符。

例如,假设我们有一个名为 Multiply 的类,它定义了一个 apply 方法。

class Multiply {
  def apply(a: Int, b: Int): Int = a * b
}

这允许您在该类的任何实例上调用运算符()。例如:

val mul = new Multiply()
println(mul(5, 6)) // prints 30

【讨论】:

【解决方案2】:

我得出的结论是,我们使用 addr(log2Up(n)-1, 0) 来获取从零开始到 log2Up(n)-1 位的地址位。举个例子吧。

如果我们以这种方式创建类 RegFile 的对象

val reg = RegFile(31, 10)

首先,创建内存 rf。该内存的大小是 31 个 UInt 类型的数据,宽度为 10,从 0 到 30。 当我们计算 log2Up(n)-1 时,我们得到 4,我们有这样的东西:addr(4,0)。这给了我们最后五位 addr。就像@Jack Koenig 在上面的评论中所说的那样:“Rocket 的寄存器文件使用了一个小技巧,与 RISC-V 相比,它在物理上颠倒了寄存器的顺序”,这就是我们使用 ~addr 的原因。至少 rf(~addr) 将我们返回该内存位置中的内容。

这是以这种方式实现的,以提供足够的内存访问。 看看如果我们尝试从我们的内存中没有的内存位置获取数据会发生什么。如果以这种方式调用方法访问

access(42)

我们尝试访问第 41 个位置的内存位置,但我们只有 31 个内存位置(30 是顶部)。 42二进制是101010。使用我上面所说的

~addr(log2Up(n)-1,0)

将返回 10101 或十进制的 21。因为寄存器的顺序是颠倒的,这是 第 10 个内存位置(我们尝试访问第 41 个但只有 31 个,41 减去 31 是 10)。

【讨论】:

  • 如果我们请求内存位置 31 会发生什么?它仍然是 5 位,所以可能会引发错误......如果这是真的,那么值 n 必须是 2 的幂,所以 32 和 31 是顶部内存位置,我们不能将 31 和 30 作为最高内存位置。还是我错过了什么?
  • 我不确定在这种情况下会发生什么,但我认为这应该会引发错误,因为我们的内存 Mem 中没有那个内存位置。我同意你的观点,n 必须是 2 的幂,但我以 n=31 为例,因为我在此处发布的火箭芯片代码就是这种情况。
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 2021-08-22
  • 1970-01-01
  • 2017-05-16
  • 2013-11-01
  • 1970-01-01
  • 2017-10-13
  • 2023-03-28
相关资源
最近更新 更多