Trouble understanding statement order in Chisel

87 Views Asked by At

Here is a simple module containing a down counter:

import chisel3.util.{Valid, DeqIO}
class Input(WIDTH : Int) extends Bundle {
  val x = UInt(WIDTH.W)
}
class Output(WIDTH : Int) extends Bundle {
  val y = UInt(WIDTH.W)
}
class DownCount(WIDTH : Int) extends Module {
  val io  = IO(new Bundle {
    val in  = DeqIO(new Input(WIDTH))
    val out = Output(Valid(new Output(WIDTH)))
  })
  val i = Reg(UInt(WIDTH.W))
  val p = RegInit(false.B)

  printf("i = %d, p = %b, out.valid = %b\n",
    i, p, io.out.valid)
  io.in.ready := !p
  io.out.valid := false.B
  io.out.bits.y := 10.U
  when (p) {
    i := i - 1.U
    when (i === 0.U) {
      printf("Before setting out.valid = %b\n", io.out.valid)
      p := false.B
      // Here the register is set to 1.
      io.out.valid := true.B
    }
  }.otherwise {
    when (io.in.valid) {
      printf("Initializing\n")
      i := WIDTH.U - 1.U
      p := true.B
    }
  }
}

Here is the output after applying the clock.step() function on the module a few times:

i =    0, p = 0, out.valid = 0
Initializing
i =    7, p = 1, out.valid = 0
i =    6, p = 1, out.valid = 0
i =    5, p = 1, out.valid = 0
i =    4, p = 1, out.valid = 0
i =    3, p = 1, out.valid = 0
i =    2, p = 1, out.valid = 0
i =    1, p = 1, out.valid = 0
i =    0, p = 1, out.valid = 1
Before setting out.valid = 1     <-- why is it 1 here??
i =  255, p = 0, out.valid = 0

How on earth can io.out.valid be 1 (true) before it is assigned the true.B value? Is Chisel reordering printf statement in some weird way?

1

There are 1 best solutions below

5
FabienM On

It seems to be normal behavior. With the := operator, the left-value will be written with right value at the end of clock cycle. out.valid is still true.B just after false.B assignation.

// i =    0, p = 1, out.valid = 1
  printf("i = %d, p = %b, out.valid = %b\n",i, p, io.out.valid) 
  io.in.ready := !p
  io.out.valid := false.B
// Here, io.out.valid is still true.B if printf was true.B
// false.B will be written at the end of cycle,
//  except if another connection write true.B
  io.out.bits.y := 10.U
  when (p) {
    i := i - 1.U
    when (i === 0.U) {
      printf("Before setting out.valid = %b\n", io.out.valid)
      p := false.B
      // Here the register is set to 1.
      io.out.valid := true.B  // Will be set to true.B (but was already true.B)
    }
  }.otherwise {
    when (io.in.valid) {
      printf("Initializing\n")
      i := WIDTH.U - 1.U
      p := true.B
    }
  }
}