Mrchacha
Mrchacha

Reputation: 317

Reassign a variable multiple times within a clock cycle - Chisel

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

Upvotes: 2

Views: 493

Answers (1)

Jack Koenig
Jack Koenig

Reputation: 6064

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.

Upvotes: 3

Related Questions