chipsalliance / chisel

Chisel: A Modern Hardware Design Language
https://www.chisel-lang.org/
Apache License 2.0
3.97k stars 595 forks source link

Difficulty with anonymous Bundles inside of parameterized Bundles #240

Closed ccelio closed 7 years ago

ccelio commented 8 years ago

I have the following code:

class DecodeUnitIo(implicit p: Parameters) extends BoomBundle()(p)     
{                                                                      
//   val enq_uop = new MicroOp().asInput  this works.

   // this throws an error message               
   val enq = new Bundle {                                              
      val uop = new MicroOp()
   }.asInput                                                           

   // this works                                                                
   val deq = new Bundle {                                              
      val uop = new MicroOp().asOutput                                 
   }                                                                   

  ...                   
   // having or not having this override changes nothing about whether it works or doesn't.
   override def cloneType: this.type = new DecodeUnitIo()(p).asInstanceOf[this.type]
}

The error message:

[error] (run-main-0) chisel3.internal.ChiselException: [error] decode.scala:359: Parameterized 
  Bundle class boom.DecodeUnitIo$$anon$1 needs cloneType method. You are probably using 
  an anonymous Bundle object that captures external state and hence is un-cloneTypeable in 
  class boom.DecodeUnit
[error] [error] decode.scala:359: Parameterized Bundle class boom.DecodeUnitIo$$anon$1 
  needs cloneType method. You are probably using an anonymous Bundle object that captures 
  external state and hence is un-cloneTypeable in class boom.DecodeUnit
[error] CODE HAS 2 ERRORS and 0 WARNINGS
chisel3.internal.ChiselException: [error] decode.scala:359: Parameterized Bundle class 
  boom.DecodeUnitIo$$anon$1 needs cloneType method. You are probably using an anonymous 
  Bundle object that captures external state and hence is un-cloneTypeable in class 
  boom.DecodeUnit
[error] decode.scala:359: Parameterized Bundle class boom.DecodeUnitIo$$anon$1 needs 
  cloneType method. You are probably using an anonymous Bundle object that captures external 
  state and hence is un-cloneTypeable in class boom.DecodeUnit
CODE HAS 2 ERRORS and 0 WARNINGS

Summary:

It either works - or doesn't work - based on the location of the .asInput. If it annotates the Bundle, we get an error. If it is appended to the elements within the Bundle, it works just fine. As these seem isomorphic, I find this very confusing as a Chisel user.

Request:

I would prefer that either:

a) a more actionable error message be displayed. It is not clear what to do, and adding a cloneType to the DecodeUnitIO bundle doesn't fix the issue!

b) this be made to work as the user would expect.

aswaterman commented 8 years ago

If you also add a cloneType method to MicroOp, does the problem go away?

sdtwigg commented 8 years ago

Would need to see the unsuppressed exception thrown but I think this is what is happening: asInput (and relatives asOutput and flip) will all call cloneType on their input. No cloneType method is defined for the user Bundle so Chisel uses java reflection to try to make one. It is a nested class so the java constructor actually takes a pointer to the parent class. However, here, the parent class is the anonymous Bundle forming the whole IO, not the Module. Chisel will only try injecting a reference to the current Module and so that fails as well.

It is tricky because the inner anonymous Bundle doesn't have a name at all so it can't really be referred to with any actual name. Does line "decode.scala: 359" at least point to the offending asInput call (which IS attached to the problematic anonymous Bundle)?

ccelio commented 8 years ago

Would need to see the unsuppressed exception thrown but I think this is what is happening:

Is there a way I can get that to you? I provided the printout to the entire stack trace that I'm currently given by running Chisel.

Does line "decode.scala: 359" at least point to the offending asInput call (which IS attached to the problematic anonymous Bundle)?

Sadly, line 359 points to the instantiation of the IO bundle:

357 class DecodeUnit(implicit p: Parameters) extends BoomModule()(p)       
358 {                                                                      
359    val io = new DecodeUnitIo                                           
ccelio commented 8 years ago

If you also add a cloneType method to MicroOp, does the problem go away?

Nope. Same error message as before:

[error] (run-main-0) chisel3.internal.ChiselException: [error] decode.scala:359: Parameterized Bundle class boom.DecodeUnitIo$$anon$1 needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable in class boom.DecodeUnit
[error] [error] decode.scala:359: Parameterized Bundle class boom.DecodeUnitIo$$anon$1 needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable in class boom.DecodeUnit
[error] CODE HAS 2 ERRORS and 0 WARNINGS
chisel3.internal.ChiselException: [error] decode.scala:359: Parameterized Bundle class boom.DecodeUnitIo$$anon$1 needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable in class boom.DecodeUnit
[error] decode.scala:359: Parameterized Bundle class boom.DecodeUnitIo$$anon$1 needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable in class boom.DecodeUnit
CODE HAS 2 ERRORS and 0 WARNINGS
    at chisel3.internal.throwException$.apply(Error.scala:13)
    at chisel3.internal.ErrorLog.checkpoint(Error.scala:38)
    at chisel3.internal.Builder$$anonfun$build$1.apply(Builder.scala:123)
    at chisel3.internal.Builder$$anonfun$build$1.apply(Builder.scala:119)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at chisel3.internal.Builder$.build(Builder.scala:119)
    at chisel3.Driver$.elaborate(Driver.scala:111)
    at chisel3.compatibility.chiselMain$.run(Main.scala:14)
    at rocketchip.TestGenerator$.delayedEndpoint$rocketchip$TestGenerator$1(Testing.scala:185)
    at rocketchip.TestGenerator$delayedInit$body.apply(Testing.scala:165)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
java.lang.RuntimeException: Nonzero exit code: 1
    at scala.sys.package$.error(package.scala:27)
    at sbt.BuildCommon$$anonfun$toError$1.apply(Defaults.scala:2077)
    at sbt.BuildCommon$$anonfun$toError$1.apply(Defaults.scala:2077)
    at scala.Option.foreach(Option.scala:236)
    at sbt.BuildCommon$class.toError(Defaults.scala:2077)
    at sbt.Defaults$.toError(Defaults.scala:39)
    at sbt.Defaults$$anonfun$runTask$1$$anonfun$apply$38$$anonfun$apply$39.apply(Defaults.scala:750)
    at sbt.Defaults$$anonfun$runTask$1$$anonfun$apply$38$$anonfun$apply$39.apply(Defaults.scala:748)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
    at sbt.std.Transform$$anon$4.work(System.scala:63)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
[error] (rocketchip/compile:run) Nonzero exit code: 1
[error] Total time: 22 s, completed Jul 21, 2016 8:05:25 PM

real    0m28.827s
user    0m45.435s
sys 0m1.283s
aswaterman commented 8 years ago

whiskey tango foxtrot... that error message is being printed by the base cloneType method, so overriding someone's cloneType method should prevent the message from being printed.

sdtwigg commented 8 years ago

I am reasonably certain the error is coming from the anonymous Bundle (assigned to enq) that contains a MicroOp. In that case, the base cloneType method is still being called. Giving that anonymous Bundle a name and defining cloneType on that would fix the problem.

aswaterman commented 8 years ago

Chris seemed to suggest the cloneType on the anonymous bundle had no effect.

ccelio commented 8 years ago

Chris seemed to suggest the cloneType on the anonymous bundle had no effect.

I added the cloneType method to the MicroOp bundle, which resides inside of the anonymous bundle, but I didn't add a cloneType to the anonymous bundle itself.

I'm sure if I gave the anonymous bundle a name and a cloneType things would work, but I don't want to give every anonymous bundle a name. :/

ducky64 commented 7 years ago

This should be solved by spamming cloneType.

Now if cloneType was spammed and this is still causing problems, then you should re-open this bug,

Long term solution is to have a Bundle annotation that automatically generates cloneType and all kinds of other fun stuff like literal creation.