在 for 循环 chisel3 中使用 yield 时如何访问前一个元素

How to access previous element when using yield in for loop chisel3

这是混合 Chisel / Scala 的问题。 背景,我需要总结很多数字(可配置的输入信号数量)。由于时间限制,我不得不将它分成 4 组并通过管道(注册),然后将其送入下一阶段(它将小 4 倍,直到我到达) 这是我的代码:

// log4 Aux function //
def log4(n : Int): Int = math.ceil(math.log10(n.toDouble) / math.log10(4.0)).toInt
// stage //
def Adder4PipeStage(len: Int,in: Vec[SInt]) : Vec[SInt] = {
    require(in.length % 4 == 0) // will not work if not a muliplication of 4
    val pipe = RegInit(VecInit(Seq.fill(len/4)(0.S(in(0).getWidth.W))))
    pipe.zipWithIndex.foreach {case(p,j) => p := in.slice(j*4,(j+1)*4).reduce(_ +& _)}
    pipe
}
// the pipeline
val adderPiped = for(j <- 1 to log4(len)) yield Adder4PipeStage(len/j,if(j==1) io.in else <what here ?>)    

如何访问前一阶段,我也愿意听听其他实现上述内容的方法

您可以在这里做几件事:

  1. 您可以只使用 var 作为“先前”值:
var prev: Vec[SInt] = io.in
val adderPiped = for(j <- 1 to log4(len)) yield {
  prev = Adder4PipeStage(len/j, prev) 
  prev
}

使用 varfor yield 有点奇怪(因为前者基本上是可变的,而后者倾向于与不可变样式代码一起使用)。

  1. 您也可以使用折叠构建 List
// Build up backwards and reverse (typical in functional programming)
val adderPiped = (1 to log4(len)).foldLeft(io.in :: Nil) {
  case (pipes, j) => Adder4PipeStage(len/j, pipes.head) :: pipes
}.reverse
 .tail // Tail drops "io.in" which was 1st element in the result List

如果你不喜欢前面折叠的反向构造,

  1. 您可以使用带 Vector 的折叠(比 List 更适合附加):
val adderPiped = (1 to log4(len)).foldLeft(Vector(io.in)) {
  case (pipes, j) => pipes :+ Adder4PipeStage(len/j, pipes.last)
}.tail // Tail drops "io.in" which was 1st element in the result Vector

最后,如果您不喜欢这些不可变的方式,您总是可以接受可变性并编写类似于 Java 或 Python:

  1. For 循环和可变集合
val pipes = new mutable.ArrayBuffer[Vec[SInt]]
for (j <- 1 to log4(len)) {
  pipes += Adder4PipeStage(len/j, if (j == 1) io.in else pipes.last)
}