Chisel will save you enormously because of both:
* Object oriented features
* Functional programming
System Verilog has great OOP features, but, last I checked, these are all strictly simulation only for most ASIC/FPGA workflows. As a consequence, I've always had two flavors of Verilog writing: OOP testbenches and painfully imperative Verilog designs in incredibly rigid design patterns that the synthesis tools like. With Chisel (or some other language that's generating a hardware description) you're completely free to design how you want at some (assumed) cost to the efficiency of the Verilog generated. The assumption is that this design trade-off is worth it. You gain hardware designer speed and immense amounts of reuse.
On the functional side, you can be ridiculously terse in the types of complex structures you want to describe which should improve designer speed while resulting in clearer more understandable code. Nonetheless, this can be difficult for pure hardware engineers initially , e.g., a portion of the CSR file of rocket:
// Description of the CSRs
object CSRs {
val fflags = 0x1
val frm = 0x2
val fcsr = 0x3
// ...
}
// A mapping of the CSR Ints above to some underlying registers
val read_mapping = collection.mutable.LinkedHashMap[Int,Bits](
CSRs.tselect -> reg_tselect,
CSRs.tdata1 -> reg_bp(reg_tselect).control.asUInt,
// ...
}
// A function that converts read_mapping to a list of boolean checks on address matches
val decoded_addr = read_mapping map { case (k, v) => k -> (io.rw.addr === k) }
// Dereference the first register that matches
io.rw.rdata := Mux1H(for ((k, v) <- read_mapping) yield decoded_addr(k) -> v)
Handling the above complexity in Verilog is an exercise in patience. In Chisel it's just an understanding of OOP, functional programming, and Scala. However, coming from C this looks unintelligible.
The problem is that most hardware designers don't have this OOP/functional exposure (or I certainly didn't!). The MOOCs do help. After all the CS nonsense, the next thing is to just get comfortable with the Chisel codebase. The tutorials, cheatsheets, and examples are all good, however, I've found it to be much more efficient to just look at the API spec (
https://chisel.eecs.berkeley.edu/api/index.html#package). Alternatively, install and use ctags so that you can do the API browsing on the command line. There is _a lot_ of interesting features which you just don't come across unless you have access to the API. If you have some module that you want to implement, look at something roughly equivalent in rocket-chip to see how Berkeley/SiFive went about it. They know what they're doing and reading good code helps. Also, Scala has a read-eval-print-loop (REPL) like python. Just install Scala and run it from the command line. That's proven invaluable for playing with some of the more alien functional program stuff (`map`, `zip`, `zipWithIndex`, `flatMap`, etc.).
Alternatively, it's relatively easy to do a direct translation of Verilog into Chisel as an initial step and then start using more and more features as your comfort level increases. This was the original path that I did and I've been pushing others down it as well.
I think you can avoid the LEC check of Chisel -> Verilog. Everything that you simulate is always Verilog (or that's how it works with the current rocket-chip approach). That's not the case with Chisel testers. So, if you do your functional verification in Verilog you then only have to worry about LEC checks during the ASIC/FPGA flow.