【问题标题】:Is there an accepted way to get a Gray Code counter in Chisel?是否有一种可接受的方式在 Chisel 中获得格雷码计数器?
【发布时间】:2020-07-09 04:48:36
【问题描述】:

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

我更喜欢格雷码而不是二进制地址循环。在 Chisel 中编写二进制计数器很容易,但我看不到格雷码计数器的规定。

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

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

【问题讨论】:

    标签: chisel gray-code


    【解决方案1】:

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

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

    以下代码使用反射二进制格雷码实现格雷码计数器。它改编自this blog post。它只会计数。它的工作方式与 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)
      }   
    
    }   
    
    

    【讨论】:

      【解决方案2】:

      与 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
        }
      }
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

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

          我认为如果你想要一个合适的 GrayCode 类型,创建一个自定义类型是合理的。不幸的是,没有办法为类似Bits 的类型扩展Data(该层次结构中的所有类型都是密封的),但您可以创建一个自定义Bundle 包装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 Typeclasses,这是一个更高级的 Scala 功能。只是提一下,以防它们看起来很陌生。

          【讨论】:

          猜你喜欢
          • 2013-05-10
          • 2014-08-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-28
          • 2023-03-24
          • 2018-08-22
          • 2011-03-24
          相关资源
          最近更新 更多