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

I designed in chisel a mesh-array of registers, say 32x32 Bytes of D-flipflop, to take a try to implement such parrallel hardware arch in chisel. The firrtl file is like 100k lines, looks like a netlist. Then the time costed by the translation from firrtl to verilog is like many hours. During this period of time the processing is just arranged on a single CPU.
Could you enlight me how to make it running parallel on CPUs?
The key codes:
val reg_vec = (0 to 31).map(i=>
(0 to 31).map(j=>
Module(new MyNodeOfReg(8))
)
)
The scala compiler and code runner version 2.11.8
I made a run batch like this, do ./run then wait for ./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
in which scalac/scala is auto-generated after scala installation
in which My Test.scala is :
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() })
}
}
The Top.scala is:
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
}
}

This sounds like a very gnarly performance bug so if you could provide more information about your design that would be very helpful (or code would be even better). You can also try using the command-line option -ll info to provide the runtime of each of the Firrtl passes.
rocket-chip-based projects frequently generate hundreds of thousands to millions of lines of firrtl which are usually compiled on the order of seconds to minutes. For this reason we have not yet felt the need to parallelize the code.
EDIT:
Thank you for adding the code!
I'm struggling to reproduce the performance problems you're seeing. With irp = 32, compilation from Firrtl to Verilog is taking about 4 seconds; total compilation including Chisel is taking about 8 seconds. Should I be changing other parameters as well? I am compiling with:
object Main extends App {
chisel3.Driver.execute(args, () => new Top)
}
Can you share a little bit more about how you're building the Module?

#jkoenig by your suggestion, I found something new.
First, as I had got the Bench.fir, so I direct run firrtl
firrtl -i Bench.fir -o my.v -X verilog
Then the verilog generated in seconds, as fast as you said. Wow~
Second, then I add this code in Top.scala
package mytest
object GenVlgTop extends App {
chisel3.Driver.execute(args, () => new Top)
}
update run
scalac -d target -cp $CP Top.scala
scala -cp $CP mytest.GenVlgTop
Then the time ./run to generate firrtl is very long as it was as before
[info] [0.002] Elaborating design...
[info] [1.290] Done elaborating.
the log stops and waits here while firrtl is not generated.
So far a solution is like this:
1. do the original ./run, when it's waiting,
2. C-c to interrupt the processing
3. firrtl the generated *.fir

Related

Using go/ast for iota declarations

I've been working with go/ast to parse go source code and copy it into another file as part of a vendoring exercise. I've got most things handled - functions, types etc - but I'm struggling with const declarations which use iota. I'm iterating through the items in ast.File.Scope.Objects and copying over the source for objects with Scope.Outer == nil and their Decl == ast.ValueSpec, basically implying top level variables and constants.
In a block of type:
const (
a = iota
b
c
d
)
...each one of them registers as a separate object, which is fair enough. However, I'm struggling to assign them with values because the objects can also be out of order when I'm iterating through them. I'm able to see the value as ast.Object.Data for these, but it also seems off when it's set to 1 << iota and so on. Does anyone have any thoughts on how I can get a grouped const declaration with the correct iota values assigned?
Thank you!
I was working on this problem for the exhaustive analyzer, which, during its enum discovery phase, needs to find constant values.
Playground: https://play.golang.org/p/nZLmgE4rJZH
Consider the following ConstDecl. It comprises of 3 ConstSpec, and each ConstSpec has 2 names. (This example uses iota, but the approach below should work generally for any ConstDecl.)
package example
const (
A, B = iota, iota * 100 // 0, 0
_, D // 1, 100
E, F // 2, 200
)
With go/ast and go/types (or x/tools/go/packages), we can obtain a *ast.GenDecl representing the above ConstDecl and a *types.Info for the package.
var decl *ast.GenDecl
var info *types.Info
The following will be true of decl.
decl.Tok == token.CONST
To obtain the constant values, we can do:
func printValuesConst(decl *ast.GenDecl, info *types.Info) {
for _, s := range decl.Specs {
v := s.(*ast.ValueSpec) // safe because decl.Tok == token.CONST
for _, name := range v.Names {
c := info.ObjectOf(name).(*types.Const)
fmt.Println(name, c.Val().ExactString())
}
}
}
This will, as expected, print:
A 0
B 0
_ 1
D 100
E 2
F 200
Side note: var instead of const
Note that the code above works for const blocks; for a var block we will have to obtain the value using v.Values[i] (assuming a value exists at the index i).
Playground: https://play.golang.org/p/f4mYjXvsvHB
decl.Tok == token.VAR
func printValuesVar(decl *ast.GenDecl, info *types.Info) {
for _, s := range decl.Specs {
v := s.(*ast.ValueSpec) // safe because decl.Tok == token.VAR
for i, name := range v.Names {
if len(v.Values) <= i {
fmt.Println(name, "(no AST value)")
continue
}
tv := info.Types[v.Values[i]]
if tv.Value == nil {
fmt.Println(name, "(not constant value)")
continue
}
fmt.Println(name, tv.Value.ExactString())
}
}
}

HackerRank task Sales by Match doesn't pass tests

I solved Sales by Match problem in this way:
package main
import (
"fmt"
)
func main() {
var amount int
_, _ = fmt.Scanf("%d", &amount)
pairs := 0
set := make(map[int]bool)
for i := 0; i < amount; i++ {
var number int
_, _ = fmt.Scanf("%d", &number)
if set[number] {
set[number] = false
pairs++
} else {
set[number] = true
}
}
println(pairs)
}
I tested it with the following input:
9
10 20 20 10 10 30 50 10 20
Here's the result:
So, as you can see, everything works fine. But when I run the tests I see the following result:
I don't understand why they are not passed, so, please, can anyone explain what's the problem in my solution? Thanks in advance I would appreciate any help
Change println(pairs) to fmt.Print(pairs)because println writes to stderr and hackerrank looks at stdout for the result.

Is there a way to make Golang compilation fail if the compiler is only a point-release too old?

Specifically, for our next software release, I want to make sure to catch a bug fix that was released in go 1.5.2; is there a way to make the build fail if our build server tries to build my code using Go 1.5.1 or earlier?
I know about Build Constraints, and I can see how I can add a build constraint of "go1.5" to make sure the "1.5 or greater" compiler is used, but "go1.5.2" doesn't work (it appears that build tags go1.5.1 and go1.5.2 are not defined.)
On a related note, I also can't find a way to dump out the build tags that apply for a build, and yet this seems to be a pretty useful thing to do.
You can use the -ldflags to pass the configured min golang build and check at init() time if the runtime matches the specified version.
package main
import "runtime"
// go run -ldflags "-X main.minGoVersion=go1.5.1" main.go
// from http://stackoverflow.com/questions/18409373/how-to-compare-two-version-number-strings-in-golang
func VersionOrdinal(version string) string {
// ISO/IEC 14651:2011
const maxByte = 1<<8 - 1
vo := make([]byte, 0, len(version)+8)
j := -1
for i := 0; i < len(version); i++ {
b := version[i]
if '0' > b || b > '9' {
vo = append(vo, b)
j = -1
continue
}
if j == -1 {
vo = append(vo, 0x00)
j = len(vo) - 1
}
if vo[j] == 1 && vo[j+1] == '0' {
vo[j+1] = b
continue
}
if vo[j]+1 > maxByte {
panic("VersionOrdinal: invalid version")
}
vo = append(vo, b)
vo[j]++
}
return string(vo)
}
var minGoVersion string
func init() {
if minGoVersion == "" {
panic("please pass -ldflags \"-X main.minGoVersion=<version string> flag\"")
}
current := VersionOrdinal(runtime.Version())
desired := VersionOrdinal(minGoVersion)
if current < desired {
panic("unsupported golang runtime " + current + " < " + desired)
}
}
func main() {
}

Why can't I key in a string in Golang map?

I'm writing a function in go to remove duplicate characters in a string. Here is my approach. When I run the following test, why do I get this error? I'm new to Go and used to more dynamic languages like Ruby/Python.
panic: assignment to entry in nil map [recovered]
panic: assignment to entry in nil map
source.go
func removeDuplicate(s string) string {
var m map[string]int
var c_string []string = strings.Split(s, "")
for i :=0; i < len(c_string); i++ {
m[c_string[i]] = 0
}
for i :=0; i < len(c_string); i++ {
m[c_string[i]] = m[c_string[i]] + 1
}
var (
result string = ""
)
for i :=0; i < len(c_string); i++ {
if m[c_string[i]] < 1 {
result = result + c_string[i]
}
}
return result
}
source_test.go
func TestRemoveDuplicateChars(t *testing.T) {
got := removeDuplicateChars("abbcde")
if got != "abcde" {
t.Fatalf("removeDuplicateChars fails")
}
}
Because you haven't actually initilize/allocated m, you've only declared it. Make this; var m map[string]int into m := map[string]int{}.
Which does initilization and assignment both in the same statement. You could also add another line m = make(map[string]int) which would prevent the error though I personally prefer the compacted syntax.
fyi your code is barfing on this line; m[c_string[i]] = 0, the error message should make sense when combining that with the information above.

How can I change the for loop iterator type?

Go uses int for the iterator by default from what I can tell, except I want uint64. I cannot figure out a way to change the type of for loop iterator in Go. Is there a way to do it inline with the for statement? The default type of int causes problems when I try to do something in the loop, like a mod operation (%).
func main() {
var val uint64 = 1234567890
for i:=1; i<val; i+=2 {
if val%i==0 {
}
}
}
./q.go:7: invalid operation: i < val (mismatched types int and uint64)
./q.go:8: invalid operation: val % i (mismatched types uint64 and int)
You mean something like this?
for i, val := uint64(1), uint64(1234567890); i<val; i+=2 {
// your modulus operation
}
http://play.golang.org/p/yAdiJu4pNC
Another option is to use a "while" loop:
package main
func main() {
var i, val uint64 = 1, 1234567890
for i < val {
if val % i == 0 {
println(i)
}
i += 2
}
}
https://golang.org/ref/spec#For_condition

Resources