Chisel中只读值重赋值运行报错问题求助
Chisel曼彻斯特加法器运行时错误分析
问题背景
编写Chisel实现曼彻斯特加法器时,编译无报错但运行阶段失败。此前编写RCA时遇到过类似问题,修改编码风格后解决,怀疑与变量/信号赋值规则相关,但未在官方文档找到明确说明。
错误代码
class ManchesterAdder(n: Int) extends Module { val io = IO(new Bundle { val a = Input(UInt(n.W)) val b = Input(UInt(n.W)) val cin = Input(UInt(1.W)) val sum = Output(UInt(n.W)) val cout = Output(UInt(1.W)) }) var chain = Module(new Manchestercarrychain(n)) chain.io.cin := io.cin for (i <- 0 until n) { chain.io.cin(i) := io.a(i) ^ io.b(i) } val sumReg = RegInit(0.U(n.W)) val coutReg = RegInit(0.U(1.W)) sumReg := chain.io.g(n - 1) ^ chain.io.p(n - 1) coutReg := chain.io.cout io.sum := sumReg io.cout := coutReg }
报错信息
[48/48] temp.run Exception in thread "main" chisel3.package.ChiselException: Cannot reassign to read-only ManchesterAdder.?: OpResultIBoc at ... ( at adder.ManchesterAdder.$anonfun$new$1(Manchester_Adder.scala:39) at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:190) at adder.ManchesterAdder.<init>(Manchester-Adder.scala:38) at adder.generates.$anonfun$new$1(generate.scala:20) at ... () ... (stack trace trimmed to user code only. Rerun with --full-stacktrace to see the full stack trace) 1 targets failed temp.run subprocess failed
错误原因
- 信号重复赋值+类型不匹配:
- 首先
chain.io.cin被赋值为io.cin(1位UInt),但后续for循环中又试图给chain.io.cin(i)赋值——1位信号没有多位索引,这本身就是逻辑错误。 - Chisel中硬件信号是单向连线,一旦完成赋值(
:=操作)就不能再修改,否则会触发"Cannot reassign to read-only"错误。这里尝试两次修改chain.io.cin,违反了Chisel的硬件建模规则。
- 首先
- 曼彻斯特进位链的输入逻辑错误:
曼彻斯特进位链的输入应该是每一位的生成项(g_i = a_i & b_i)和传递项(p_i = a_i ^ b_i),而不是把p_i赋值给cin端口,代码混淆了进位链的输入端口定义。
修复方案
步骤1:确认Manchestercarrychain的IO定义
确保其Bundle包含正确的端口:
class Manchestercarrychain(n: Int) extends Module { val io = IO(new Bundle { val g = Input(UInt(n.W)) // 每一位的生成项 val p = Input(UInt(n.W)) // 每一位的传递项 val cin = Input(UInt(1.W)) // 最低位进位输入 val cout = Output(UInt(1.W))// 最高位进位输出 val c = Output(UInt(n.W)) // 每一位的进位输出(用于计算sum) }) // 进位链实现逻辑... }
步骤2:修正加法器代码
class ManchesterAdder(n: Int) extends Module { val io = IO(new Bundle { val a = Input(UInt(n.W)) val b = Input(UInt(n.W)) val cin = Input(UInt(1.W)) val sum = Output(UInt(n.W)) val cout = Output(UInt(1.W)) }) val chain = Module(new Manchestercarrychain(n)) // 连接进位链的生成项和传递项 for (i <- 0 until n) { chain.io.g(i) := io.a(i) & io.b(i) chain.io.p(i) := io.a(i) ^ io.b(i) } chain.io.cin := io.cin // 仅赋值一次 // 计算每一位的sum:sum_i = p_i ^ c_i val sum = Wire(UInt(n.W)) for (i <- 0 until n) { sum(i) := chain.io.p(i) ^ chain.io.c(i) } // 若不需要寄存器直接输出,可去掉Reg val sumReg = RegNext(sum) val coutReg = RegNext(chain.io.cout) io.sum := sumReg io.cout := coutReg }
关键修正点
- 不再重复赋值
chain.io.cin,仅连接1位的进位输入。 - 将
a(i)^b(i)正确赋值给进位链的p(i)端口,a(i)&b(i)赋值给g(i)端口。 - 每一位的sum由对应位的传递项和进位异或得到,而非仅取最后一位的g和p。
内容的提问来源于stack exchange,提问作者peak
相关产品推荐
相关产品推荐

