2

我正在寻找在 Chisel3 中编写用于寻址子单元的计数器。如果计数器与子单元中的某个寄存器匹配,则子单元会触发,否则不会。

我宁愿用格雷码而不是二进制的地址循环。用 Chisel 编写二进制计数器很容易,但我看不到格雷码计数器的规定。

我可以编写一种类似于 Uint 和 Sint 的新类型,但如果它已经存在,我不愿意重新发明它。然而,我在食谱或其他文档中没有看到任何关于格雷码的内容。Github 只是出现了一个面向 Minecraft 的 repo(因为它与“chisel”匹配) VHDL 有现有的东西,但我想用 Chisel 来表达这一点。

那么我是否错过了可以在 Chisel 中提供灰色计数器的资源?如果做不到这一点,构建类似于 Uint 的新类型是一种合理的继续方式吗?

4

4 回答 4

1

我快速环顾四周,没有发现任何与您要找的东西非常相似的东西。我能找到的最接近的东西是火箭芯片中的一个简单的灰色计数器(https://github.com/chipsalliance/rocket-chip/blob/29ce00180f2a69947546d6385a1da86cbc584376/src/main/scala/util/AsyncQueue.scala#L49)但它使用常规二进制计数,然后只返回UInt格雷码。它也没有利用任何 Scala 类型安全性。

我认为这将是一个合理的构建方式,如果您愿意,可以将其贡献给https://github.com/freechipsproject/ip-contributions以提高可见性。

我认为如果你想要一个合适的GrayCode类型,创建一个自定义类型是合理的。不幸的是,没有办法扩展Data类似Bits- 的类型(该层次结构中的所有类型都是密封的),但是您可以创建一个Bundle包装 a 的自定义,UInt然后实现您自己的一组操作,例如。

class GrayCode(private val w: Int) extends Bundle {
  val value = UInt(w.W)

  def +(that: GrayCode): GrayCode = ???
}
object GrayCode {
  // Lets you write GrayCode(4.W)
  // Width is defined in chisel3.internal.firrtl though which is awkward...
  def apply(width: Width): GrayCode = ???
}

这只是一个速写。DSP 工具库有 DSP 的自定义类型示例:https ://github.com/ucb-bar/dsptools

他们倾向于大量使用Scala 类型类,这是一个更高级的 Scala 特性。只是提一下,以防它们看起来很陌生。

于 2020-03-28T21:59:22.963 回答
1

你可以看看这个链接programmersought gray code fifo,它看起来可能是相关的,但我不熟悉它。

于 2020-03-29T00:49:47.890 回答
0

似乎这里的所有实现都使用二进制到灰色的转换。对于异步 FIFO,这仅在格雷码在跨越时钟域之前被锁存时才有效。如果您想要一个实际计数格雷码而不是将二进制值转换为格雷码的计数器怎么办?

一种选择是将灰度转换为二进制,相加,然后再转换回灰度并存储结果。另一种是使用自定义算法来计算序列中的下一个灰度值。典型的序列是反射二进制格雷码,但也存在其他序列。

下面的代码使用反射二进制格雷码实现格雷码计数器。它改编自这篇博文。它只会计数。它的工作方式与 Chisel Counter 对象类似,但它添加了对同步重置和自定义寄存器名称的支持。它返回计数器和包装状态。

import chisel3._
import chisel3.util._

// a Gray counter counts in Gray code
object GrayCounter {

  // Gray unit cell
  // b is the current state of this bit
  // returns (t, z_o) where t is the next state of this bit
  def grayCell(b: Bool, q_i: Bool, z_i: Bool, enable: Bool, parity: Bool): (Bool, Bool) = { 
    (b ^ (enable && q_i && z_i && parity), (!q_i) && z_i)
  }   

  // cond = counts when true
  // n = count value, must be a power of 2
  // synchronousReset = resets counter to 0
  // name = name for this counter
  def apply(cond: Bool, n: Int, synchronousReset: Bool = false.B, name: String = null) = { 
    require(isPow2(n), s"Gray counter must have power-of-2 length (you asked for $n)")
    require(n > 2, s"Gray counter minimum count is 4 (you asked for $n)")
    val counter = RegInit(0.U(log2Ceil(n).W))
    if (name != null) {
      counter.suggestName(name)
    }   
    val counterNext = Wire(Vec(log2Ceil(n), Bool()))
    counter := counterNext.asUInt
    val z_wires = Wire(Vec(log2Ceil(n), Bool()))
    val parity = counter.xorR
    for (i <- 0 until log2Ceil(n)) {
      if (i == 0) {
        val grayCellOut = grayCell(counter(i), true.B, true.B, cond, !parity)
        counterNext(i) := grayCellOut._1
        z_wires(i) := grayCellOut._2
      } else {
        val grayCellOut = grayCell(counter(i), counter(i-1) || (i == log2Ceil(n)-1).B, 
            z_wires(i-1) || (i == 1).B, cond, parity)
        counterNext(i) := grayCellOut._1
        z_wires(i) := grayCellOut._2
      }   
    }   
    when (synchronousReset) {
      counter := 0.U 
    }   
    val wrap = counter === (n/2).U && cond
    (counter, wrap)
  }   

}   

于 2021-03-03T22:15:15.397 回答
0

与 Jack 一样,我不熟悉在格雷码中实际增加值所需的数学运算,但类似以下代码的代码会将格雷码转换为二进制,添加,然后将其转换回格雷码。我不确定下面的 Vec() 代码是否可以正常工作,但应该清楚地说明这个想法。

import chisel3._
import chisel3.util._

class GrayCode(private val w: Int) extends Bundle {
  val value = UInt(w.W)

  def bin2grey(x : UInt) : UInt = {
    x ^ (x >> 1.U)
  }
  def grey2bin(x : UInt, n : Int) : UInt = {
    val tmp = Wire(Vec(n, Bool()))
    tmp(n-1) := x(n-1)
    for (i <- 0 to (n-2)) {
      tmp(i) := x(i) ^ tmp(i+1)
    }
    Cat(tmp.reverse)
  }
  def +(that: GrayCode): GrayCode = {
    val sum = new GrayCode(w)
    sum.value := grey2bin(bin2grey(this.value) + bin2grey(that.value), w)
    sum
  }
}
于 2020-04-08T13:58:52.963 回答