ucb-bar / chisel2-deprecated

chisel.eecs.berkeley.edu
388 stars 90 forks source link

val differs from expression after assignment #713

Open pw-gecos opened 8 years ago

pw-gecos commented 8 years ago

I am writing an interrupt controller in Chisel.

The following function determines the highest priority pending interrupt. Each interrupt source is represented by a IRQStatusReg and the combined register file is a Chisel Vec. To determine the interrupt with the highest priority, a recursive divide and conquer strategy is used. In hardware, this should be synthesized as a tree of multiplexers. The returned tuple contains the register and its ID.

def select_highest_prio_irq(vec: Vec[IRQStatusReg], start: Int, len: Int) : (IRQStatusReg, UInt) = {
    if(len == 1){
        return (vec(start), UInt(width=0))
    }
    else{
       val left_len = len / 2
       val right_len = len - left_len
       val (left, l0) = select_highest_prio_irq(vec, start, left_len)
       val (right, r0) = select_highest_prio_irq(vec, start+ left_len, right_len)
       val select_left = left.irq_pending && !left.irq_masked && left.irq_prio > right.irq_prio
       printf("val: %x\n", select_left)
       printf("expr: %x\n", left.irq_pending && !left.irq_masked && left.irq_prio > right.irq_prio)
       (Mux(select_left, left, right), 
        Cat(!select_left, Mux(select_left, l0, r0)))  
    }
 } 
 val (highest_prio_reg, irq_nr) = select_highest_prio_irq(irq_status_regfile, 0, intSources)

However, this function fails to determine the correct result when using certain register configurations and 4 interrupt sources. The reason lies in the assignment to select_left: The value of the expression on the right hand side differs from the value select_left has after the assignment (see line 3/4):

val:0 
expr: 0
val:0
expr: 1
val: 1
expr: 1

How is that possible? How can a val have a different value than an expression after an assignment?

For reference, here is the definition of the IRQStatusReg Vec:

class IRQStatusReg(priorityLevels: Int) extends Bundle {
  val irq_prio = UInt(width = log2Up(priorityLevels))
  val irq_masked = Bool()
  val irq_pending = Bool()
  override def cloneType: this.type =
      new IRQStatusReg(priorityLevels).asInstanceOf[this.type]
}
val irq_status_regfile = Reg(init = Vec(intSources, new IRQStatusReg(priorityLevels)))

Curiously enough, the code behaves as expected when I rewrite the function like this:

 def select_highest_prio_irq(vec: Vec[IRQStatusReg], start: Int, len: Int) : (IRQStatusReg, UInt) = {
    if(len == 1){
        return (vec(start), UInt(start))
    }
    else{
        val left_len = len / 2
        val right_len = len - left_len
        val (left, l0) = select_highest_prio_irq(vec, start, left_len)
        val (right, r0) = select_highest_prio_irq(vec, start + left_len, right_len)
        val select_left = (left.irq_pending && !left.irq_masked && (left.irq_prio >= right.irq_prio)) 
        val mux_reg = Mux(select_left, left, right)
        val mux_nr = Mux(select_left, l0, r0)
        (mux_reg, mux_nr)  
    }
 }