Переназначить переменную несколько раз в течение такта - долото

Я хотел бы переназначить переменную hit_bits несколько раз в течение одного такта. hit_bits будет увеличиваться всякий раз, когда io.bits_perf.bits(i) правда. Я получаю "НАЙДЕННЫЙ КОМБИНАЦИОННЫЙ ПУТЬ!" когда я пытаюсь скомпилировать код.

Любая идея?

  val hit_bits = Bits()
  hit_bits := Bits(0)

  when(io.bits_perf.valid){
    for(i<- 0 until 3){
      when(io.bits_perf.bits(i)) { hit_bits := hit_bits + Bits(1) 
      }
    }
  }

1 ответ

Решение

Для этого примера важно иметь в виду разницу между долотом и скалой. Более конкретно, when является долотной конструкцией, которая сопоставляется с условными связями в Verilog, тогда как for это конструкция Scala, которую мы можем использовать для генерации оборудования (аналогично generate в Верилоге).

Давайте развернем это для цикла и посмотрим, что мы получим:

when(io.bits_perf.valid){
  when(io.bits_perf.bits(0)) { hit_bits := hit_bits + Bits(1) }
  when(io.bits_perf.bits(1)) { hit_bits := hit_bits + Bits(1) }
  when(io.bits_perf.bits(2)) { hit_bits := hit_bits + Bits(1) }
}

Обратите внимание, что все соединения одинаковы, когда io.bits_perf.valid высокий, и любой из битов в io.bits_perf.bits высокий, вы будете подключаться hit_bits в hit_bits + Bits(1), Это комбинационный цикл.

Теперь давайте разберемся, как выразить то, что вы действительно пытаетесь сделать: как связать hit_bits с количеством единиц в io.bits_perf.bits когда io.bits_perf.valid в приоритете. Это также известно как popcount, для которого у Chisel просто так есть утилита. Что вы должны сделать, это использовать это:

  val hit_bits = Bits()
  hit_bits := Bits(0)

  when(io.bits_perf.valid) {
    hit_bits := PopCount(io.bits_perf.bits)
  }

Однако код, который вы написали, близок к исправлению, поэтому давайте все равно заставим его работать. Мы хотим использовать цикл Scala for для генерации кода. Один из способов сделать это - использовать переменную Scala (которая позволяет переназначение) в качестве своего рода "указателя" на узлы долота, а не val, который допускает только одно присваивание (и, следовательно, не может быть изменен, чтобы указывать на другой узел долота).).

var hit_bits = Bits(0, 2) // We set the width because + does not expand width
when (io.bits_perf.valid) {
  for (i <- 0 until 3) {
    hit_bits = hit_bits + io.bits_perf.bits(i)
  }
}
// Now hit_bits is equal to the popcount of io.bits_perf.bits (or 0 if not valid)

Обратите внимание, что я также удалил внутреннее, когда условно, так как вы можете просто добавить бит напрямую, а не условно, добавив 1. Что здесь происходит, так это то, что hit_bits является ссылкой на узлы долота, начиная с 0, Затем для каждого индекса в цикле for мы меняем узел, который hit_bits относится к узлу Chisel, который является выходом сложения предыдущего упомянутого узла hit_bits и немного io.bits_perf.bits,

Другие вопросы по тегам