ucb-bar / chisel2-deprecated

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

No warning when defined out of order #587

Closed da-steve101 closed 8 years ago

da-steve101 commented 8 years ago

Had a cryptic error message that was difficult to debug. Came down to a null pointer from things defined out of order but wasn't detected. It seems to be when assigning to the Vec (perhaps Bundle in general but i haven't tested)

class UserMod extends Module {
  val io = new Bundle {
    val in = UInt(INPUT, 4)
    val out = Vec.fill(2) { UInt(OUTPUT, 4) }
    // val out2 = UInt(OUTPUT, 8)
  }
  val mem = Vec.fill(4) { Reg(UInt(width = 8)) }
  for ( i <- 0 until 2 ) {
    io.out(i) := mem(counter)(7 - 4*i, 4 - 4*i) // Cryptic errors here
  }
  // io.out2 := mem(counter) // This has good warning
  val counter = RegInit(UInt(0, 2))
  counter := counter + UInt(1, 2)
  mem(counter) := ( UInt(0, 4) ## io.in )
}

Here is the error message

[info] [0.047] // COMPILING < (class BadOrderSuite$UserMod$1)>(0)
[info] [0.069] giving names
[info] [0.082] executing custom transforms
[info] [0.083] adding clocks and resets
[info] [0.092] inferring widths
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.Bool(OUTPUT, width=1, connect to 1 inputs: (T10[Chisel.Extract] in BadOrderSuite$UserMod$1)) ? /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (T4[Chisel.BinaryOp] in BadOrderSuite$UserMod$1)) : REG(mem_1) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node 0x1 and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.Bool(OUTPUT, width=1, connect to 1 inputs: (T19[Chisel.Extract] in BadOrderSuite$UserMod$1)) ? /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (T13[Chisel.Mux] in BadOrderSuite$UserMod$1)) : /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (T2[Chisel.Mux] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (mem_1[Chisel.Reg] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*T5*/ Extract(/*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (T6[Chisel.BinaryOp] in BadOrderSuite$UserMod$1)), 0x0, 0x0) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (counter[Chisel.RegReset] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*io_in in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(INPUT, width=4, connect to 0 inputs: ()) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.Bool(OUTPUT, width=1, connect to 1 inputs: (T10[Chisel.Extract] in BadOrderSuite$UserMod$1)) ? /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (T4[Chisel.BinaryOp] in BadOrderSuite$UserMod$1)) : REG(mem_1) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node 0x1 and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.Bool(OUTPUT, width=1, connect to 1 inputs: (T19[Chisel.Extract] in BadOrderSuite$UserMod$1)) ? /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (T13[Chisel.Mux] in BadOrderSuite$UserMod$1)) : /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (T2[Chisel.Mux] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (mem_1[Chisel.Reg] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*T5*/ Extract(/*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (T6[Chisel.BinaryOp] in BadOrderSuite$UserMod$1)), 0x0, 0x0) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (counter[Chisel.RegReset] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*io_in in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(INPUT, width=4, connect to 0 inputs: ()) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.Bool(OUTPUT, width=1, connect to 1 inputs: (T10[Chisel.Extract] in BadOrderSuite$UserMod$1)) ? /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (T4[Chisel.BinaryOp] in BadOrderSuite$UserMod$1)) : REG(mem_1) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node 0x1 and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.Bool(OUTPUT, width=1, connect to 1 inputs: (T19[Chisel.Extract] in BadOrderSuite$UserMod$1)) ? /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (T13[Chisel.Mux] in BadOrderSuite$UserMod$1)) : /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (T2[Chisel.Mux] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=8, connect to 1 inputs: (mem_1[Chisel.Reg] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*T5*/ Extract(/*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (T6[Chisel.BinaryOp] in BadOrderSuite$UserMod$1)), 0x0, 0x0) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*? in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(OUTPUT, width=None, connect to 1 inputs: (counter[Chisel.RegReset] in BadOrderSuite$UserMod$1)) and non-Node NullSentinel in class TestSuite
[error] TestSuite.scala:97: can't compare Node /*io_in in <BadOrderSuite_UserMod_1 (class BadOrderSuite$UserMod$1)>*/ Chisel.UInt(INPUT, width=4, connect to 0 inputs: ()) and non-Node NullSentinel in class TestSuite
Re-running Chisel in debug mode to obtain erroneous line numbers...
CPP elaborate
[info] [0.055] // COMPILING < (class BadOrderSuite$UserMod$1)>(0)
[info] [0.057] giving names
[info] [0.059] executing custom transforms
[info] [0.059] adding clocks and resets
[info] [0.061] inferring widths
[info] BadOrderSuite:
[info] - badOrder *** FAILED ***
[info]   java.lang.NullPointerException:
[info]   at Chisel.Driver$.idfs(Driver.scala:255)
[info]   at Chisel.Backend.inferAll(Backend.scala:516)
[info]   at Chisel.Backend.elaborate(Backend.scala:841)
[info]   at Chisel.CppBackend.elaborate(Cpp.scala:1362)
[info]   at Chisel.Driver$.execute(Driver.scala:93)
[info]   at Chisel.Driver$.apply(Driver.scala:41)
[info]   at Chisel.Driver$.apply(Driver.scala:46)
[info]   at Chisel.Driver$.apply(Driver.scala:52)
[info]   at Chisel.chiselMain$.apply(hcl.scala:63)
[info]   at Chisel.chiselMainTest$.apply(hcl.scala:76)
[info]   ...

For out2 in the example code above you get the nice warning such as:

[warn] /home/.../BadOrderSuite.scala:19: Reference to uninitialized value counter
[warn]       io.out2 := mem(counter)
[warn]                     ^
[warn] one warning found
sdtwigg commented 8 years ago

This is an underlying issue with how Scala works. (I suppose the argument can be made that Chisel entices you to put so much in the Module constructor, which is somewhat non-ideal as it manifests this issue.)

All of the vals (and defs and vars*) become fields of the ultimate underlying Scala/Java object. Hence how you can reference them later with the dot operator. When the constructor is executed, the vals and vars are initialized 'in-order' of their declaration in the constructor (also in-between any statements that need to be executed. Note that you can access defs or lazy vals 'out-of-order' (although flaws in the current Chisel implementation make using lazy val very dangerous) since they really define functions that don't require initialization.

The scala compiler tries to catch some of these errors (hence seeing the out2 issue) but apparently misses some. You may want to raise this case with the scalac developers. They are in the process of unveiling a redone compiler toolchain so it may be a good time to ask to improve the invalid reference detection.

(* You should generally avoid using vars)