能否使用Record类创建RegInit?动态生成寄存器报错求助
用自定义Record类生成RegInit时的Chisel绑定错误解决
我尝试通过自定义Record类生成RegInit,在Module中动态创建携带额外信息的RegInit。已知Bundle继承自Record,且用Bundle能成功生成RegInit,但自定义Record却触发绑定错误。
代码示例
class MyReg(reg_info: List[(String, UInt)]) extends Record { override def elements: ListMap[String, UInt] = ListMap( reg_info.map( x => x._1 -> x._2 ):_* ) override def cloneType: MyReg.this.type = new MyReg(reg_info).asInstanceOf[this.type] } class reg_test(reg_list: List[(String, String, List[(String, Int)])]) extends Module with RegSugar { val io = IO(new Bundle() { val a = Input(UInt(16.W)) val b = Input(UInt(16.W)) val d = Output(UInt(16.W)) val e = Output(UInt(16.W)) }) val myBundle = new Bundle() { val a = UInt(16.W) val b = UInt(16.W) } val reg_init_bundle = RegInit(myBundle, 0.U.asTypeOf(myBundle)) println(reg_init_bundle) reg_init_bundle.a := io.a reg_init_bundle.b := io.b val list_b = List(("a", UInt(16.W)), ("b", UInt(16.W))) val myRecord = new MyReg(list_b) val reg_init = RegInit(myRecord, 0.U.asTypeOf(myRecord)) reg_init.elements("a") := io.a reg_init.elements("b") := io.b io.d := reg_init.elements("a") + reg_init.elements("b") io.e := reg_init_bundle.a + reg_init_bundle.b }
报错信息
Exception in thread "main" chisel3.package$RebindingException: Attempted reassignment of binding to reg_test.reg_init_?.a: Wire[UInt<16>], from: ChildBinding(reg_test.reg_init_?: Reg[MyReg]) at ... () at implicit_test.reg_test.$anonfun$reg_init$2(reg_test.scala:61) at chisel3.internal.prefix$.apply(prefix.scala:48) at implicit_test.reg_test.$anonfun$reg_init$1(reg_test.scala:61) at chisel3.internal.plugin.package$.autoNameRecursively(package.scala:33) at implicit_test.reg_test.<init>(reg_test.scala:61) at implicit_test.reg_test$.$anonfun$verilogString$1(reg_test.scala:77) at ... () at ... (Stack trace trimmed to user code only. Rerun with --full-stacktrace to see the full stack trace)
问题原因
Bundle虽然继承自Record,但Chisel对Bundle做了特殊处理:它会自动将内部元素与父Bundle的绑定关联。而自定义的MyReg直接继承Record时,elements中的UInt是在构造实例时就初始化的Wire节点,当把MyReg传给RegInit时,这些已绑定为Wire的元素无法被重新绑定为Reg的子元素,因此触发RebindingException。
解决方法
修改自定义Record类,确保元素延迟初始化,且克隆类型而非复用原UInt实例:
修正后的MyReg类
class MyReg(reg_info: List[(String, UInt)]) extends Record { // 用lazy val延迟元素初始化,避免提前创建Wire绑定 override lazy val elements: ListMap[String, UInt] = ListMap( reg_info.map { case (name, tpe) => name -> tpe.cloneType // 克隆类型,创建新的硬件节点 }:_* ) override def cloneType: MyReg.this.type = new MyReg(reg_info).asInstanceOf[this.type] }
修正赋值逻辑
避免直接访问elements,改用Record自带的括号运算符访问元素:
val reg_init = RegInit(myRecord, 0.U.asTypeOf(myRecord)) // 用括号访问元素,而非直接操作elements reg_init("a") := io.a reg_init("b") := io.b io.d := reg_init("a") + reg_init("b")
关键说明
RegInit会为传入的数据类型创建Reg实例,并将其元素绑定为Reg的子节点,若元素已绑定为其他硬件节点(如Wire)则会触发绑定冲突。lazy val延迟elements初始化,确保元素在Record被绑定为Reg时才创建,避免提前生成Wire节点。- Record的
apply(name)方法是访问元素的标准方式,比直接操作elements更符合Chisel设计规范,也能避免潜在的绑定问题。
内容的提问来源于stack exchange,提问作者XINGYU YAN
相关产品推荐
相关产品推荐

