chisel 可以在 parallel/multi cpu 中将 firrtl 翻译成 verilog 吗?

can chisel translates firrtl to verilog in parallel/multi cpu?

我在 chisel 中设计了一个寄存器网状数组,比如 32x32 字节的 D 触发器,以尝试在 chisel 中实现这种并行硬件架构。 firrtl 文件有 100k 行,看起来像一个网表。那么从firrtl到verilog的翻译所花费的时间就像很多小时一样。这段时间处理刚好安排在单CPU上。 你能告诉我如何在 CPU 上使它 运行 并行吗?

关键代码:

val reg_vec = (0 to 31).map(i=>
                (0 to 31).map(j=>
                  Module(new MyNodeOfReg(8))
  )
)

scala 编译器和代码运行ner version 2.11.8

我做了一个这样的 运行 批处理,执行 ./运行 然后等待 ./target/Bench.v:

mkdir target
cp /opt/eda_tool/RISCV/top.cpp target
scalac -d target -cp $CP Top.scala Test.scala
scala  -cp $CP org.scalatest.run Test

其中scalac/scala是scala安装后自动生成的 其中我的 Test.scala 是:

import chisel3._
import chisel3.util._
import chisel3.testers._
import org.scalatest._
import org.scalacheck._
import org.scalatest.prop._
import scala.sys.process._

class Bench() extends BasicTester {
  val dut = Module(new Top())
  val t = Reg(UInt(width=32),init=0.U)
  t := t+1.U

  when(t<=1.U) {
  }.elsewhen(t===100.U) {
    stop()
  }
}

class Test extends PropSpec with PropertyChecks {

  property("elaborate") {
    Driver.elaborate (() => { new Top() })
  }

  property("should return the correct result") {
    TesterDriver.execute(() => { new Bench() })
  }

}

Top.scala是:

import chisel3._
import chisel3.util._

object ce_pm{
  val div = 4
  val e = 1   
  val ec= 1   
  val p = 10 // 16/div        
  val s = p*p       
  val w = s*e       

  val ext = 64      
  val extw= ext*e   

  val irp = 20 // 40/div  // InREG parameter
  val irn = irp*irp // InREG reg number
}

class Mux4(n: Int) extends Module {
  val io = IO(new Bundle{
    val i = Input(Vec(4,UInt(n.W)))
    val s = Input(UInt(2.W))
    val o = Output(UInt(n.W))
  })
  val mux00 = Wire(UInt(n.W))
  val mux01 = Wire(UInt(n.W))
  mux00 := Mux(io.s(0)===1.U,io.i(1),io.i(0))
  mux01 := Mux(io.s(0)===1.U,io.i(3),io.i(2))
  io.o  := Mux(io.s(1)===1.U,mux01,mux00)
}

class CEIO_TwoD_Torus extends Bundle {
  val n = Input(UInt(ce_pm.e.W))
  val s = Input(UInt(ce_pm.e.W))
  val w = Input(UInt(ce_pm.e.W))
  val e = Input(UInt(ce_pm.e.W))
}

class TwoD_TorusReg extends Module {
  val io = IO(new Bundle{
    val i = new CEIO_TwoD_Torus()
    val o = new CEIO_TwoD_Torus().flip
    val d = Input(UInt(ce_pm.e.W)) 
    val c = Input(Vec(4,UInt(1.W)))
  })
  val r = Reg(UInt(ce_pm.e.W),init=0.U)
  val u_mux4 = Module(new Mux4(ce_pm.e))
  u_mux4.io.i(0) := io.i.e
  u_mux4.io.i(1) := io.i.s
  u_mux4.io.i(2) := io.i.w
  u_mux4.io.i(3) := io.i.n
  u_mux4.io.s    := Cat(io.c(2),io.c(1))
  when (io.c(0) === 1.U) {
    when (io.c(3) === 0.U) {
      r := u_mux4.io.o
    } .otherwise {
      r := io.d
    }
  } 
  io.o.e := r
  io.o.s := r
  io.o.w := r
  io.o.n := r
}

class Top extends Module {
  val io = IO(new Bundle{
    val i = Input (UInt(ce_pm.extw.W))
    val o = Output(Vec(ce_pm.p,Vec(ce_pm.p,UInt(ce_pm.e.W))))
    val c = Input (UInt(7.W))
  })
  val n  = ce_pm.irp
  val r_vec = (0 to n-1).map ( i=>
                (0 to n-1).map ( j=>
                  Module(new TwoD_TorusReg)
                )
              )
  for (i <- 0 to n-1) {
    for (j <- 0 to n-1) {
      r_vec(i)(j).io.c(0) := io.c(1)
      r_vec(i)(j).io.c(3) := io.c(0)
      r_vec(i)(j).io.c(2) := io.c(2)
      r_vec(i)(j).io.c(1) := io.c(3)
    }
  }
  // out
  val m = ce_pm.p
  for (i <- 0 to m-1) {
    for (j <- 0 to m-1) {
      io.o(i)(j) := r_vec(i)(j).io.o.e
    }
  }
  //2-D-Torus interconnection
  for (i <- 1 to n-1) {
    for (j <- 1 to n-1) {
      r_vec(i)(j).io.i.w := r_vec(i)(j-1).io.o.e
      r_vec(i)(j).io.i.n := r_vec(i-1)(j).io.o.s
    }
  }
  for (i <- 0 to n-2) {
    for (j <- 0 to n-2) {
      r_vec(i)(j).io.i.e := r_vec(i)(j+1).io.o.w
      r_vec(i)(j).io.i.s := r_vec(i+1)(j).io.o.n
    }
  }
  for (i <- 0 to n-1) {
    r_vec(i)(0).io.i.w := r_vec(i)(n-1).io.o.e
    r_vec(0)(i).io.i.n := r_vec(n-1)(i).io.o.s
  }
}

这听起来像是一个非常棘手的性能错误,所以如果您能提供更多关于您的设计的信息,那将非常有帮助(或者代码会更好)。您还可以尝试使用命令行选项 -ll info 来提供每个 Firrtl 遍的运行时间。

基于

rocket-chip 的项目经常会生成数十万到数百万行的 firrtl,这些 firrtl 通常按秒到分钟的顺序编译。出于这个原因,我们还没有觉得需要并行化代码。

编辑: 感谢您添加代码!

我正在努力重现您所看到的性能问题。使用 irp = 32,从 Firrtl 到 Verilog 的编译大约需要 4 秒;包括 Chisel 在内的总编译大约需要 8 秒。我还应该更改其他参数吗?我正在编译:

object Main extends App {
  chisel3.Driver.execute(args, () => new Top)
} 

您能否分享更多有关如何构建模块的信息?

@jkoenig 根据你的建议,我发现了一些新东西。

首先,由于我已经拿到了Bench.fir,所以我直接运行 firrtl

firrtl -i Bench.fir -o my.v -X verilog

然后verilog秒生成,跟你说的一样快。哇~

其次,然后我在Top.scala

中添加这段代码
package mytest
object GenVlgTop extends App {
  chisel3.Driver.execute(args, () => new Top)
}

更新运行

scalac -d target -cp $CP Top.scala 
scala  -cp $CP mytest.GenVlgTop

然后./运行生成firrtl的时间和以前一样很长

[info] [0.002] Elaborating design...
[info] [1.290] Done elaborating.

当 firrtl 未生成时,日志会在此处停止并等待。

目前解决方案是这样的:

1. do the original ./run, when it's waiting, 
2. C-c to interrupt the processing
3. firrtl the generated *.fir