在一个时钟周期内多次重新分配变量 - Chisel
Reassign a variable multiple times within a clock cycle - Chisel
我想在单个时钟周期内多次重新分配变量 hit_bits
。只要 io.bits_perf.bits(i)
为真,hit_bits
就会增加。当我尝试编译代码时,我得到 "FOUND COMBINATIONAL PATH!"。
有什么想法吗?
val hit_bits = Bits()
hit_bits := Bits(0)
when(io.bits_perf.valid){
for(i<- 0 until 3){
when(io.bits_perf.bits(i)) { hit_bits := hit_bits + Bits(1)
}
}
}
对于这个例子,重要的是要记住 Chisel 和 Scala 之间的区别。更具体地说,when
是映射到 Verilog 中的条件连接的 Chisel 结构,而 for
是我们可以用来生成硬件的 Scala 结构(类似于 Verilog 中的 generate
)。 =25=]
让我们展开这个 for 循环,看看我们得到了什么:
when(io.bits_perf.valid){
when(io.bits_perf.bits(0)) { hit_bits := hit_bits + Bits(1) }
when(io.bits_perf.bits(1)) { hit_bits := hit_bits + Bits(1) }
when(io.bits_perf.bits(2)) { hit_bits := hit_bits + Bits(1) }
}
请注意,所有连接都是相同的,当 io.bits_perf.valid
为高且 io.bits_perf.bits
中的任何位为高时,您将连接 hit_bits
到 hit_bits + Bits(1)
.这是组合循环。
现在,让我们弄清楚如何表达您真正想要做的事情:当 io.bits_perf.valid
很高时,如何将 hit_bits 连接到 io.bits_perf.bits
中的个数。这也称为 popcount,Chisel 恰好有一个实用程序。你应该做的是使用:
val hit_bits = Bits()
hit_bits := Bits(0)
when(io.bits_perf.valid) {
hit_bits := PopCount(io.bits_perf.bits)
}
但是,您编写的代码几乎是正确的,所以让我们让它正常工作吧。我们想要做的是使用 Scala for 循环来生成一些代码。一种方法是使用 Scala var(允许重新分配)作为对 Chisel 节点的 "pointer" 而不是 val 只允许单一赋值(因此不能更改为指向不同的 Chisel 节点)。
var hit_bits = Bits(0, 2) // We set the width because + does not expand width
when (io.bits_perf.valid) {
for (i <- 0 until 3) {
hit_bits = hit_bits + io.bits_perf.bits(i)
}
}
// Now hit_bits is equal to the popcount of io.bits_perf.bits (or 0 if not valid)
请注意,我在有条件时也删除了内部,因为您可以直接添加位而不是有条件地添加 1。这里发生的是 hit_bits
是对 Chisel 节点的引用,以 0
。然后,对于 for 循环中的每个索引,我们将 hit_bits 节点更改为 Chisel 节点,该节点是前一个节点 hit_bits 和 [=17 的一点相加的输出=].
我想在单个时钟周期内多次重新分配变量 hit_bits
。只要 io.bits_perf.bits(i)
为真,hit_bits
就会增加。当我尝试编译代码时,我得到 "FOUND COMBINATIONAL PATH!"。
有什么想法吗?
val hit_bits = Bits()
hit_bits := Bits(0)
when(io.bits_perf.valid){
for(i<- 0 until 3){
when(io.bits_perf.bits(i)) { hit_bits := hit_bits + Bits(1)
}
}
}
对于这个例子,重要的是要记住 Chisel 和 Scala 之间的区别。更具体地说,when
是映射到 Verilog 中的条件连接的 Chisel 结构,而 for
是我们可以用来生成硬件的 Scala 结构(类似于 Verilog 中的 generate
)。 =25=]
让我们展开这个 for 循环,看看我们得到了什么:
when(io.bits_perf.valid){
when(io.bits_perf.bits(0)) { hit_bits := hit_bits + Bits(1) }
when(io.bits_perf.bits(1)) { hit_bits := hit_bits + Bits(1) }
when(io.bits_perf.bits(2)) { hit_bits := hit_bits + Bits(1) }
}
请注意,所有连接都是相同的,当 io.bits_perf.valid
为高且 io.bits_perf.bits
中的任何位为高时,您将连接 hit_bits
到 hit_bits + Bits(1)
.这是组合循环。
现在,让我们弄清楚如何表达您真正想要做的事情:当 io.bits_perf.valid
很高时,如何将 hit_bits 连接到 io.bits_perf.bits
中的个数。这也称为 popcount,Chisel 恰好有一个实用程序。你应该做的是使用:
val hit_bits = Bits()
hit_bits := Bits(0)
when(io.bits_perf.valid) {
hit_bits := PopCount(io.bits_perf.bits)
}
但是,您编写的代码几乎是正确的,所以让我们让它正常工作吧。我们想要做的是使用 Scala for 循环来生成一些代码。一种方法是使用 Scala var(允许重新分配)作为对 Chisel 节点的 "pointer" 而不是 val 只允许单一赋值(因此不能更改为指向不同的 Chisel 节点)。
var hit_bits = Bits(0, 2) // We set the width because + does not expand width
when (io.bits_perf.valid) {
for (i <- 0 until 3) {
hit_bits = hit_bits + io.bits_perf.bits(i)
}
}
// Now hit_bits is equal to the popcount of io.bits_perf.bits (or 0 if not valid)
请注意,我在有条件时也删除了内部,因为您可以直接添加位而不是有条件地添加 1。这里发生的是 hit_bits
是对 Chisel 节点的引用,以 0
。然后,对于 for 循环中的每个索引,我们将 hit_bits 节点更改为 Chisel 节点,该节点是前一个节点 hit_bits 和 [=17 的一点相加的输出=].