Ali Sed
Ali Sed

Reputation: 151

Reference is not fully initialized

I have a module like below:

class ComputationIO[T <: Data](val OperandType: T) extends Bundle {
    val data = OperandType.cloneType
}

class Computation [T <: Data] (OperandType: T) extends Module {
    val io = IO( new Bundle {
        val in = Input(new ComputationIO(OperandType))
    })
    // REST OF THE CODE HERE...
}

And, I'm instantiating the Computation like below:

    val compUnit  = for (i <- 0 until nParal) yield {
        val Comp =  Module(new Computation(UInt(32.W)))
        Comp
    }

However, although I'm passing UInt(32.W) to the constructor, it gives me the following error:

firrtl.passes.CheckInitialization$RefNotInitializedException:Reference compUnit is not fully initialized.                                                                                                                                                           
[error]    : compUnit.io.in.OperandType <= VOID  

I can solve the problem by removing the val in the IO class and overriding the cloneType, sth like below:

class ComputationIO[T <: Data](OperandType: T) extends Bundle {
    val data = OperandType.cloneType

    override def cloneType = new ComputationIO(OperandType).asInstanceOf[this.type ]
} 

But, I was wondering what is the problem of the first approach? The constructor has been initialized. So, the not fully initialized error doesn't make sense.

Thanks

Upvotes: 2

Views: 1329

Answers (1)

Jack Koenig
Jack Koenig

Reputation: 6064

The documentation linked in the other answer mentions this but I want to highlight a piece:

The only caveat is if you are passing something of type Data as a “generator” parameter, in which case you should make it a private val.

This is due to the fact that if you make a class parameter a val, it becomes a public field of the class. The hardware fields of a Bundle are defined to be "the public fields of the class of type Data". Thus, val OperandType is a field of the class, it would be the same as writing:

class ComputationIO[T <: Data](_operandType: T) extends Bundle {
    val OperandType = _operandType
    val data = OperandType.cloneType
}

In fact, you only need to call cloneType on OperandType because you get field aliasing with OperandType and data being the exact same object. This is obviously only an issue because you unintentionally have OperandType as a public field of the Bundle.

You can deal with this by making it a private val which will not cause it to become a field of the Bundle:

class ComputationIO[T <: Data](private val OperandType: T) extends Bundle {
    val data = OperandType // note .cloneType not necessary
}

Note that beginning in Chisel v3.4.3, there is opt-in Autoclonetype2 which does not require parameters to be vals to be able to infer clonetype, you can see the release notes for more information. Autoclonetype2 will become the default in Chisel v3.5.0 (not yet released).

Upvotes: 6

Related Questions