【问题标题】:Designing a filter using scala - For loop unrolling使用 scala 设计过滤器 - 用于循环展开
【发布时间】:2020-03-08 00:54:19
【问题描述】:

我正在尝试使用 Chisel 创建一个可合成的 FIR 滤波器。我正在从 csv 文件中读取有符号整数,然后将其作为系数传递给 FIR 滤波器类。只是为了给大家一个味道 - 这就是系数的样子:

-152651856 1233223 ...

然后使用 for 循环对滤波器的系数进行 MAC 操作。我找不到 for 循环未正确展开的原因。它只是将最后一个系数合成为常数。

class FIR (val coefficients:Array[Int], val count:Int ) extends Module {
  val io = IO(new Bundle {
    val X        = Input(Vec(count,SInt(16.W)))
    val Y_out     = Output(SInt(64.W))
  })

  val sum  = Reg(SInt(64.W))
  sum := 0.S(64.W)
  val temp = Reg(Vec(count,SInt(64.W)))


  for(ct <- 0 until count ) {

   temp(ct) := new  fromIntToLiteral(coefficients(ct): Int).S
   sum := sum + temp(ct) * io.X(ct)

  }
  io.Y_out := sum

}

这里的数组coefficients是传递给类的滤波器系数,count是系数的数量。

【问题讨论】:

    标签: scala chisel


    【解决方案1】:

    要记住的重要一点是,Chisel 不是行为综合。没有阻塞分配(尽管可以模拟)。相反,Chisel 具有 最后一个连接语义,因此最后一个连接获胜。这主要在后面的连接被断言(即由when 保护)时很有用,但对于覆盖默认值也很有用。

    要查看发生了什么,让我们为 count 选择一个值并展开循环:

    // Let count = 4
    temp(0) := new  fromIntToLiteral(coefficients(0): Int).S                        
    sum := sum + temp(0) * io.X(0)
    temp(1) := new  fromIntToLiteral(coefficients(1): Int).S
    sum := sum + temp(1) * io.X(1)
    temp(2) := new  fromIntToLiteral(coefficients(2): Int).S
    sum := sum + temp(2) * io.X(2)
    temp(3) := new  fromIntToLiteral(coefficients(3): Int).S
    sum := sum + temp(3) * io.X(3)
    

    Last connect 与以下内容相同:

    temp(0) := new  fromIntToLiteral(coefficients(0): Int).S                        
    // sum := sum + temp(0) * io.X(0)
    temp(1) := new  fromIntToLiteral(coefficients(1): Int).S
    // sum := sum + temp(1) * io.X(1)
    temp(2) := new  fromIntToLiteral(coefficients(2): Int).S
    // sum := sum + temp(2) * io.X(2)
    temp(3) := new  fromIntToLiteral(coefficients(3): Int).S
    sum := sum + temp(3) * io.X(3) // <--- Winning connect to sum
    

    您可能想要做的是在 for 循环执行时增量创建总和,就像在 Verilog 中使用阻塞分配一样。我们可以模拟使用var(一个我们可以重新分配的变量)来保存中间值的行为:

      val sum  = Reg(SInt(64.W))
      val temp = Reg(Vec(count,SInt(64.W)))
    
      var sumVar = 0.S(64.W)
      for(ct <- 0 until count ) {
       temp(ct) := coefficients(ct).S
       sumVar = sumVar + temp(ct) * io.X(ct)
      }
      sum := sumVar    // Connect the finished logic to the sum's "next" value.
      io.Y_out := sum  // Connect current value of sum register to output
    

    我想在这里强调几点:

    1. 请注意,我们使用= 代替sumVar,将其视为指向硬件节点的指针。我们正在更新指针以指向我们在每次迭代中构建的新逻辑

    2. 我可能误解了您的意图,因为我的代码看起来不像我熟悉的 FIR(编辑:代码是正确的,请参阅 cmets on this answer)。请注意,在 Chisel 中,Reg 对应于触发器的实际寄存器或数组。它像 Verilog regReg 在这里描述:https://www.chisel-lang.org/chisel3/sequential-circuits.html。您还可以查看Chisel Bootcamp,它始终使用 FIR 滤波器作为激励示例。

    3. 我注意到您直接使用fromIntToLiteral。这是一个真正不应该面向用户的隐式类。你可以只写coefficients(ct).S,只要你写import chisel3._,Scala 就会让它在你不注意的情况下工作。如果您想了解更多细节,隐式是如何在 Scala 中实现Extension Methods。当您 import chisel3._ 时,.S 方法隐含地来自 fromIntToLiteral 并使其看起来S 是在 Int 上定义的方法。将其视为语法糖,使 Chisel 代码更便于编写。

    【讨论】:

    • 感谢@jack-koenig 写得很好的回答。仅仅因为您提到了它 - 我已经有了滤波器的系数,因此我不需要实现 Chisel Bootcamp 中提到的滑动函数。因此,剩下的就是你帮助我完成的 MAC 操作了。
    • 哦,太好了,谢谢你教我一些新东西! sumVar 正在执行乘法累加,所以我相信我的答案中的代码是正确的。我编辑了我的答案以添加一些您可能感兴趣的关于 fromIntToLiteral 的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2021-07-06
    • 2016-10-27
    • 1970-01-01
    相关资源
    最近更新 更多