So, I have a theoretical question about the Chisel code transformation.
I know Chisel is actually a set of Scala definitions, so it is compiled to Java bytecodes, which in turn run in the JVM and, just like a magic, it spits out Verilog equivalent description and even C++ description for older versions of Chisel.
The point is that I could not figure out how this "magic" works. My guess is that the code transformation from Chisel to Verilog/C++ is all based on Scala reflection. But I'm not sure about it as I could not find anything related to this topic.
So, is it about reflection? If so, is it compile time our runtime reflection? Can someone please give me a clue?
Thanks a lot.
Fundamentally, writing Chisel is writing a Scala program to generate a circuit. What you're describing sounds a bit like High-Level Synthesis which is quite different from Chisel. Rather than mapping Scala (or Java) primitives to hardware, Chisel executes Scala code to construct a hardware AST that is then compiled to Verilog.
I'll try to make this a little more clear with an annotated example.
// The body of a Scala class is the default constructor
// MyModule's default constructor has a single Int argument
// Superclass Module is a chisel3 Class that begins construction of a hardware module
// Implicit clock and reset inputs are added by the Module constructor
class MyModule(width: Int) extends Module {
  // io is a required field for subclasses of Module
  // new Bundle creates an instance of an anonymous subclass of Chisel's Bundle (like a struct)
  // When executing the function IO(...), Chisel adds ports to the Module based on the Bundle object
  val io = IO(new Bundle {
    val in = Input(UInt(width.W)) // Input port with width defined by parameter
    val out = Output(UInt()) // Output port with width inferred by Chisel
  }) 
  // A Scala println that will print at elaboration time each time this Module is instantiated
  // This does NOT create a node in the Module AST
  println(s"Constructing MyModule with width $width")
  // Adds a register declaration node to the Module AST
  // This counter register resets to the value of input port io.in
  // The implicit clock and reset inputs feed into this node
  val counter = RegInit(io.in)
  // Adds an addition node to the hardware AST with operands counter and 1
  val inc = counter + 1.U // + is overloaded, this is actually a Chisel function call
  // Connects the output of the addition node to the "next" value of counter
  counter := inc
  // Adds a printf node to the Module AST that will print at simulation time
  // The value of counter feeds into this node
  printf("counter = %d\n", counter) 
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With