I would like to reassign the variable hit_bits
multiple times during a single clock cycle. hit_bits
will be increased whenever io.bits_perf.bits(i)
is true. I'm getting "FOUND COMBINATIONAL PATH!" when I try to compile the code.
Any idea?
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)
}
}
}
For this example, it is important to keep in mind the difference between Chisel and Scala. More specifically, when
is a Chisel construct that maps to conditional connections in Verilog, whereas for
is a Scala construct that we can use to generate hardware (similar to generate
in Verilog).
Let's unroll this for loop and see what we get:
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) }
}
Note that all of the connections are the same, when io.bits_perf.valid
is high and any of the bits in io.bits_perf.bits
is high, you will be connecting hit_bits
to hit_bits + Bits(1)
. This is the combinational loop.
Now, let's figure out how to express what you're really trying to do: how to connect hit_bits to the number of ones in io.bits_perf.bits
when io.bits_perf.valid
is high. This is also known as a popcount for which Chisel just so happens to have a utility. What you should do is use that:
val hit_bits = Bits()
hit_bits := Bits(0)
when(io.bits_perf.valid) {
hit_bits := PopCount(io.bits_perf.bits)
}
However, the code you wrote is close to correct so let's make it work anyway. What we want to do is use a Scala for loop to do some code generation. One way to do this is to use a Scala var (which allows reassignment) as kind of a "pointer" to Chisel nodes rather than a val which only allows single assignment (and thus can't be changed to point to a different Chisel node).
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)
Note that I also dropped the inner when conditional since you can just add the bit directly rather than conditionally adding 1. What is happening here is that hit_bits
is a reference to Chisel nodes, starting with 0
. Then, for each index in the for loop, we change the node hit_bits refers to to be the Chisel node that is the output of addition of the previous node hit_bits referred to and a bit of io.bits_perf.bits
.