Переназначить переменную несколько раз в течение такта - долото
Я хотел бы переназначить переменную 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
,