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
我在 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