You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Chisel模块中使用子模块:无法为io输入赋值的问题

问题:Chisel中模块间IO接口赋值报错"Reassignment to val"

我尝试实现一个简单的计数器,用于统计从启动到包含max_count_S在内的总秒数。为简化流程,先创建了一个“信号”计数器(SignalCounter),仅在signal输入为高电平时利用时钟进行计数。

import chisel3._

/*
  |While signal is active, it counts [start,max_count] clock cycles.
*/
class SignalCounter(start_value: Int = 0, width: Int, max_count: Int) extends Module {
  val io = IO(new Bundle {
    val signal = Input(Bool())
    val out = Output(UInt(width.W))
  })

  val counter_reg = RegInit(start_value.U(width.W))

  when(io.signal)
  {
    //Whenever we get the signal; Update the counter_reg
    counter_reg := Mux(counter_reg === max_count.U(width.W),0.U ,counter_reg + 1.U)
  }

  io.out := counter_reg
}

目标是使用两个这样的计数器:

  • 第一个的max_count设为每秒时钟周期数减1,使其每过一秒输出0
  • 第二个的signal输入在第一个输出0时置高,以此统计已过去的秒数

尝试实现的代码如下:

import chisel3._

import scala.math._

def calculateBitsNeeded(N: Int): Int = {
  ceil(log10(N.toDouble + 1) / log10(2)).toInt
}


/*
  arg: cc_to_S: Number of clock cycles per second
 */
class TimeCounter(cc_to_S: Int = (100000000-1),timestep_S: Int = 0, width: Int, max_count_S: Int) extends Module {
  val io = IO(new Bundle {
    val out_s = Output(UInt(width.W))
  })


  val sig_counter_clock = new SignalCounter(max_count = cc_to_S, width =calculateBitsNeeded(cc_to_S)) //we take the cc_to_S - 1, because we want to it to tick every clock cycle we hit 1 second, not after.
  val sig_counter_S = new SignalCounter(max_count = max_count_S, width = calculateBitsNeeded(max_count_S))

  sig_counter_clock.io.signal = true.B
}

运行后出现错误:

Reassignment to val

请问是否有方法在模块内为io引脚赋值?此问题仅关注模块间io接口的实现,不涉及方案架构。


解答

错误原因

Chisel中模块的IO端口是val类型(不可变引用),用普通赋值符号=修改sig_counter_clock.io.signal会触发"Reassignment to val"错误。Chisel要求硬件信号之间的连接必须用信号赋值操作符:=,而非Scala的变量赋值=。

修正后的代码

import chisel3._
import scala.math._

def calculateBitsNeeded(N: Int): Int = {
  ceil(log10(N.toDouble + 1) / log10(2)).toInt
}

class SignalCounter(start_value: Int = 0, width: Int, max_count: Int) extends Module {
  val io = IO(new Bundle {
    val signal = Input(Bool())
    val out = Output(UInt(width.W))
  })

  val counter_reg = RegInit(start_value.U(width.W))

  when(io.signal) {
    counter_reg := Mux(counter_reg === max_count.U(width.W), 0.U, counter_reg + 1.U)
  }

  io.out := counter_reg
}

/*
  arg: cc_to_S: Number of clock cycles per second
 */
class TimeCounter(cc_to_S: Int = (100000000-1), timestep_S: Int = 0, width: Int, max_count_S: Int) extends Module {
  val io = IO(new Bundle {
    val out_s = Output(UInt(width.W))
  })

  // 正确实例化硬件模块,必须用Module(...)包裹
  val sig_counter_clock = Module(new SignalCounter(max_count = cc_to_S, width = calculateBitsNeeded(cc_to_S)))
  val sig_counter_S = Module(new SignalCounter(max_count = max_count_S, width = calculateBitsNeeded(max_count_S)))

  // 用:=连接硬件信号,替代Scala的=赋值
  sig_counter_clock.io.signal := true.B
  // 按需求连接秒计数器的触发信号:时钟计数器输出0时计数
  sig_counter_S.io.signal := sig_counter_clock.io.out === 0.U
  // 将秒计数器输出连接到顶层模块输出
  io.out_s := sig_counter_S.io.out
}

关键说明

  1. 模块实例化:必须用Module(...)包裹模块构造函数,这是Chisel生成硬件结构的标准方式,直接new SignalCounter(...)的写法无法正确生成硬件。
  2. 信号连接规则:所有硬件IO端口的赋值都要用:=,这是Chisel中表示硬件信号线连接的专属语法。
  3. 接口补全:按照需求补充了秒计数器的触发信号连接,以及顶层输出与秒计数器的连接。

内容的提问来源于stack exchange,提问作者BurgerMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:33:27