user3567895
user3567895

Reputation: 668

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

This is mix Chisel / Scala question. Background, I need to sum up a lot of numbers (the number of input signals in configurable). Due to timing constrains I had to split it to groups of 4 and pipe(register it), then it is fed into next stage (which will be 4 times smaller, until I reach on) this is my code:

// 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 ?>)    

how to I access the previous stage, I am also open to hear about other ways to implement the above

Upvotes: 2

Views: 236

Answers (1)

Jack Koenig
Jack Koenig

Reputation: 6064

There are several things you could do here:

  1. You could just use a var for the "previous" value:
var prev: Vec[SInt] = io.in
val adderPiped = for(j <- 1 to log4(len)) yield {
  prev = Adder4PipeStage(len/j, prev) 
  prev
}

It is a little weird using a var with a for yield (since the former is fundamentally mutable while the latter tends to be used with immutable-style code).

  1. You could alternatively use a fold building up a 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

If you don't like the backwards construction of the previous fold,

  1. You could use a fold with a Vector (better for appending than a 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

Finally, if you don't like these immutable ways of doing it, you could always just embrace mutability and write something similar to what one would in Java or Python:

  1. For loop and mutable collection
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)
}

Upvotes: 3

Related Questions