在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 }
关键说明
- 模块实例化:必须用
Module(...)包裹模块构造函数,这是Chisel生成硬件结构的标准方式,直接new SignalCounter(...)的写法无法正确生成硬件。 - 信号连接规则:所有硬件IO端口的赋值都要用
:=,这是Chisel中表示硬件信号线连接的专属语法。 - 接口补全:按照需求补充了秒计数器的触发信号连接,以及顶层输出与秒计数器的连接。
内容的提问来源于stack exchange,提问作者BurgerMan
相关产品推荐
相关产品推荐

