Есть ли общепринятый способ получить счетчик кода Грея в Chisel?

Я хочу написать счетчики в Chisel3, которые будут использоваться для адресации подразделений. Если счетчик совпадает с некоторым регистром в субъединице, то субблок срабатывает, в противном случае - нет.

Я бы предпочел, чтобы цикл адресов был в коде Грея, чем в двоичном. Достаточно легко написать двоичный счетчик в Chisel, но я не вижу возможности для счетчика кода Грея.

Я могу написать новый тип, похожий на Uint и Sint, но я не хочу изобретать его заново, если он уже существует. Тем не менее, я ничего не вижу в кулинарной книге или других документах о коде Грея. Github просто открывает репозиторий, ориентированный на Minecraft (потому что он соответствует "chisel"). Для VHDL уже есть материал, но я хочу выразить это в Chisel.

Так я пропустил ресурс, который предоставил бы серый счетчик в Chisel? В противном случае, является ли создание нового типа, подобного Uint, разумным способом продолжения?


person Tehom - Tom Breton    schedule 28.03.2020    source источник


Ответы (4)


Я быстро осмотрелся и не нашел ничего похожего на то, что вы ищете. Ближайшее, что я смог найти, - это простой счетчик Грея в ракетном чипе (https://github.com/chipsalliance/rocket-chip/blob/29ce00180f2a69947546d6385a1da86cbc584376/src/main/scala/util/AsyncQueue#L49) двоичный счет, а затем просто возвращает UInt в коде Грея. Он также не использует преимущества безопасности типов Scala.

Я думаю, что это было бы разумным вариантом для создания, и если вы хотите, вы можете внести его в https://github.com/freechipsproject/ip-contributions для большей наглядности.

Я думаю, что если вам нужен правильный тип GrayCode, было бы разумно создать собственный тип. К сожалению, нет способа расширить Data для типа Bits (все типы в этой иерархии запечатаны), но вы можете создать собственный 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 Tools есть примеры пользовательских типов для DSP: https://github.com/ucb-bar/dsptools

Они часто используют классы типов Scala, что является более продвинутой функцией Scala. Упомяну на случай, если какой-то синтаксис в них выглядит чуждым.

person Jack Koenig    schedule 28.03.2020
comment
Я написал и поспособствовал этому. Сейчас он живет по адресу github.com/tehom/ip-contributions.git Я раздвоил репо только потому, что я, похоже, не мог напрямую продвигать свой вклад - возможно, проблема с моей стороны. - person Tehom - Tom Breton; 22.04.2020

Вы можете взглянуть на эту ссылку программисты искали серый код FIFO, похоже это может быть актуально, но в остальном я с ним не знаком.

person Chick Markley    schedule 29.03.2020

Как и в случае с Джеком, я не знаком с математикой, необходимой для фактического увеличения значений в коде Грея, но что-то вроде следующего кода преобразует код Грея в двоичный, добавляет, а затем преобразует его обратно в код Грея. Я не уверен, что приведенный ниже код 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
  }
}
person Guy Hutchison    schedule 08.04.2020

Похоже, что все реализации здесь используют преобразование двоичного кода в серый. Для асинхронных 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)
  }   

}   

person stevo    schedule 03.03.2021