简体   繁体   English

是否有一种可接受的方法可以在 Chisel 中获得格雷码计数器?

[英]Is there an accepted way to get a Gray Code counter in Chisel?

I'm looking to write counters in Chisel3 that will be used to address subunits.我希望在 Chisel3 中编写计数器,用于寻址子单元。 If the counter matches some register in a subunit then the subunit fires, otherwise it doesn't.如果计数器与子单元中的某个寄存器匹配,则子单元触发,否则不触发。

I would much rather have the addresses cycle in Gray code than in binary.我宁愿用格雷码而不是二进制来循环地址。 It's easy enough to write a binary counter in Chisel, but I see no provision for a Gray code counter.在 Chisel 中编写二进制计数器很容易,但我看不到格雷码计数器的规定。

I can write a new type akin to Uint and Sint, but I'm reluctant to reinvent it if it's already out there.我可以编写一种类似于 Uint 和 Sint 的新类型,但如果它已经存在,我不愿意重新发明它。 Yet I don't see anything in the cookbook or other docs about Gray code.然而,我在食谱或其他关于格雷码的文档中没有看到任何内容。 Github just turns up a Minecraft-oriented repo (because it matches "chisel") There is existing stuff for VHDL but I want to express this in Chisel. Github 刚刚打开了一个面向 Minecraft 的 repo(因为它匹配“chisel”) 有 VHDL 的现有内容,但我想在 Chisel 中表达这一点。

So have I missed a resource that would provide a Gray counter in Chisel?那么我是否错过了可以在 Chisel 中提供灰色计数器的资源? Failing that, is building a new type akin to Uint a reasonable way to proceed?如果做不到这一点,构建一个类似于 Uint 的新类型是一种合理的方式吗?

I did a quick look around and didn't find anything quite like what you're looking for.我快速环顾四周,没有找到与您要查找的内容完全相同的内容。 The closest thing I could find was a simple Gray counter in rocket-chip ( https://github.com/chipsalliance/rocket-chip/blob/29ce00180f2a69947546d6385a1da86cbc584376/src/main/scala/util/AsyncQueue.scala#L49 ) but it uses regular binary counting and then just returns a UInt in Gray code.我能找到的最接近的东西是 Rocket-chip 中的一个简单的灰色计数器( https://github.com/chipsalliance/rocket-chip/blob/29ce00180f2a69947546d6385a1da86cbc584376/src/main/scala/util/AsyncQueue.scala但它# L49 )使用常规的二进制计数,然后只返回格雷码中的UInt It also doesn't take advantage of any Scala type safety.它也没有利用任何 Scala 类型安全。

I think this would be a reasonable thing to build, and if you want you could contribute it to https://github.com/freechipsproject/ip-contributions for increased visibility.我认为这将是一个合理的构建,如果您愿意,可以将其贡献给https://github.com/freechipsproject/ip-contributions以提高知名度。

I think if you wanted a proper GrayCode type, it would be reasonable to create a custom type.我认为如果你想要一个合适的GrayCode类型,创建一个自定义类型是合理的。 Unfortunately, there is no way to extend Data for a Bits -like type (all of the types in that hierarchy are sealed), but you could create a custom Bundle that wraps a UInt and then implement your own set of operations, eg.不幸的是,没有办法为类似Bits的类型(该层次结构中的所有类型都是密封的)扩展Data ,但是您可以创建一个包装UInt的自定义Bundle ,然后实现您自己的一组操作,例如。

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 = ???
}

This is just a quick sketch.这只是一个快速草图。 The DSP Tools library has examples of custom types for DSP: https://github.com/ucb-bar/dsptools DSP 工具库包含 DSP 自定义类型的示例: https : //github.com/ucb-bar/dsptools

They tend to use Scala Typeclasses a lot which is a more advanced Scala feature.他们倾向于大量使用Scala 类型类,这是一个更高级的 Scala 特性。 Just mentioning in case some of the syntax in their looks alien.只是提到以防万一他们看起来陌生的一些语法。

您可能会查看此链接程序员搜索灰色代码 fifo似乎它可能相关但我不熟悉它。

As with Jack I'm not familiar with the math needed to actually increment values in Gray code, but something like the following code would convert Gray code to binary, add, then convert it back to Gray code.与 Jack 一样,我不熟悉在格雷码中实际递增值所需的数学运算,但类似于以下代码的代码会将格雷码转换为二进制,相加,然后将其转换回格雷码。 I'm not sure if the Vec() code below would work correctly but should make the idea clear.我不确定下面的 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
  }
}

It seems like all implementations here use binary-to-Gray conversion.似乎这里的所有实现都使用二进制到灰色的转换。 For asynchronous FIFOs, this only works if the Gray code is latched just before crossing clock domains.对于异步 FIFO,仅当格雷码在跨越时钟域之前被锁存时才有效。 What if you want a counter that actually counts Gray codes instead of converting binary values to Gray codes?如果您想要一个实际计算格雷码而不是将二进制值转换为格雷码的计数器怎么办?

One option is to convert Gray to binary, add, then convert back to Gray and store the result.一种选择是将格雷转换为二进制,相加,然后再转换回格雷并存储结果。 The other is to use custom arithmetic to calculate the next Gray value in the sequence.另一种是使用自定义算法计算序列中的下一个灰度值。 The typical sequence is a reflected-binary Gray code, but others exist.典型的序列是反射二进制格雷码,但也存在其他序列。

The code below implements a Gray code counter using a reflected-binary Gray code.下面的代码使用反射二进制格雷码实现格雷码计数器。 It was adapted from this blog post .它改编自这篇博文 It only counts up.它只会计数。 It works like the Chisel Counter object, except it adds support for a synchronous reset and custom register name.它的工作方式类似于 Chisel Counter 对象,但它增加了对同步复位和自定义寄存器名称的支持。 It returns the counter and wrap status.它返回计数器和包装状态。

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

}   

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM