chipsalliance / chisel

Chisel: A Modern Hardware Design Language
https://www.chisel-lang.org/
Apache License 2.0
3.9k stars 585 forks source link

Pass Chisel information to firtool to generate debug information for the Tywaves project #4015

Open rameloni opened 4 months ago

rameloni commented 4 months ago

I have started to work on a better version for my type-based waveform viewer for Tydi and Chisel-related projects (Tywaves).

My chisel fork: https://github.com/rameloni/chisel/tree/tywaves-annotations

Currently, I created a demo to show potential features of types in waveforms and prove its feasibility. Therefore, it only works with a restricted number of cases so far. The demo is divided into 2 main parts:

Although the approach I used for the demo works for some cases, there are some drawbacks related to that both practical and technical. Because of that the need for an integration within the chisel elaboration infrastructure.

The current approach and drawbacks: chisel side

In my demo, I create an external library for chisel that:

This leads to the following issues:

  1. First of all, it accesses and uses the Chisel IR which is private to chisel3. This may compromise compatibility with future chisel versions.
  2. IDs are based on source locators and variable names. This causes for example issues when I have multiple instances of the same module (its internal signals have the same source locators, currently not working in the demo).
  3. It relies on HGLDD which can also change in the future since it is not stable and realized for synopsys.
  4. In addition HGLDD mainly contains Firrtl-to-Verilog information (except for source locators in chisel). This requires a new file format.

During a CIRCT meeting a few weeks ago, I had the opportunity to present my project and show the demo. Fabian Schuiki and I agreed that these issues would be solved if I managed to pass Chisel information directly to firtool, also simplifying the code itself. This can be achieved by propagating "Chisel IR information" during the elaboration phase to "Firrtl IR" (from here this GitHub issue).

I explain the drawbacks in a bit more detail here: https://github.com/rameloni/tywaves-chisel-demo?tab=readme-ov-file#drawbacks

New approach: integration during Chisel elaboration and Firtool

To solve the issues of the current demo, I need a systematic method to map Chisel values to Firrtl. In this way, I could provide firtool with the emission of a (new) debug file format. In addition:

Implementation of the new approach in Chisel

Chisel allows passing arbitrary metadata to FIRRTL associated with more targets (elements in a FIRRTL circuit) through the annotation mechanism. The toTarget() function can be used to reference a scala object with a FIRRTL target. Therefore, associating each target with its concrete scala/chisel information.

My goal with this issue is to write an implementation to:

rameloni commented 4 months ago

Tracking supported chisel constructs emitted in FIRRTL annotations

These tables summarize which chisel constructs are currently supported and related commit.

Module types

Module type TypeName String Annotation supported? Tested emission? Commit
Normal module (Module/RawModule) Name of the module class :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Blackbox Name of the blackbox class :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Intrinsic Name of the intrinsic class :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Classes Name of the Class class :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Parametrized modules (MyModule[T]) Module[T] :wrench: :hourglass:
Module with parameter (MyModule(n: Int)) Module(n) :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/d4d633102370427d7b4a8d49519d7e43d4d59a80
Submodule instances (any type) Name of the instance module class :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800 and https://github.com/rameloni/chisel/commit/0353ef126f4acab10a5170a144ed6eb553f746c3

Chisel Data types

Ground type TypeName String Annotation supported? Tested emission? Commit
Clock Clock :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Synchronous reset Bool :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Asynchronous reset AsyncReset :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Abstract reset Reset :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Bool Bool :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
UInt UInt :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
SInt SInt :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Analog Analog :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Aggregate type TypeName String Annotation supported? Tested emission? Commit
Bundle (anonymous) AnonymousBundle :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Bundle (user defined) Name of the defined class :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Vec of type T T[Dim1][Dim2][..][DimN] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
MixedVec MixedVec :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Nested bundles Name of the top bundle :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
User defined parametrized types (MyBundle[T]) MyType[T] :hourglass: :wrench: :hourglass:
User defined types with parameters (MyBundle(n: Int)) MyType(n) :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/d4d633102370427d7b4a8d49519d7e43d4d59a80 and https://github.com/rameloni/chisel/commit/0353ef126f4acab10a5170a144ed6eb553f746c3
DecoupledIO Should be same as bundle :soon: :soon:

Hardware bindings

Binding TypeName String Annotation supported? Tested emission? Commit
Port of type T IO[T] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Port of type T in submodules IO[T] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
Wire of type T Wire[T] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/18153de8b0aeaf1d0a2ed3e7bb086022e6b074ff
Wire of type T in submodules Wire[T] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/18153de8b0aeaf1d0a2ed3e7bb086022e6b074ff
Reg of type T Reg[T] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/18153de8b0aeaf1d0a2ed3e7bb086022e6b074ff
Reg of type T in submodules Reg[T] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/18153de8b0aeaf1d0a2ed3e7bb086022e6b074ff

Memories

Memory type TypeName String Annotation supported? Tested emission? Commit
ROM (with Vec[T]) T[size] :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800 and https://github.com/rameloni/chisel/commit/ff1de98fce44950d137dacc156da85dba8d3bddd
SyncReadMem SyncReadMem[T[size]] :white_check_mark: (:question: if the memory is of aggregate type, the fields of aggregates are annotated only when the memory is effectively used. Namely, when the MPORT is effectively instantiated) :white_check_mark: https://github.com/rameloni/chisel/commit/ff1de98fce44950d137dacc156da85dba8d3bddd
Mem Mem[T[size]] :white_check_mark: (:question: if the memory is of aggregate type, the fields of aggregates are annotated only when the memory is effectively used. Namely, when the MPORT is effectively instantiated) :white_check_mark: https://github.com/rameloni/chisel/commit/ff1de98fce44950d137dacc156da85dba8d3bddd
SRAMs SramTarget[T[size]] + SRAMInterface utility bundle :white_check_mark: :white_check_mark: https://github.com/rameloni/chisel/commit/ff1de98fce44950d137dacc156da85dba8d3bddd

Others

Type TypeName String Annotation supported? Tested emission? Commit
ChiselEnum :white_check_mark: :white_check_mark: (testing the emission was not needed since the EnumAnnotations already cover it, but testing its elaboration yes) https://github.com/rameloni/circt/releases/tag/v0.1.2-tywaves-SNAPSHOT and https://github.com/rameloni/tywaves-rs/releases/tag/v0.1.3-SNAPSHOT
Decoders :soon: :soon:
Properties :soon: :soon:
Layers :soon: :soon:
Functional abstraction (scala meta programming) ? (Counter, Mux...) Not sure if it needs support
rameloni commented 4 months ago

Update of 19-04-2024

I have already done some work on that: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800

So far I:

  1. Created a TywavesAnnotation (firrtl) case class to represent the annotation
  2. Created a companion object to generate the respective ChiselAnnotations for Chisel circuit: it parses a chisel circuit, extracts the necessary information from each component, and annotates each FIRRTL target
  3. Created AddTywavesAnnotations phase to add the TywavesAnnotation to the elaborated Chisel circuit
  4. Updated ChiselStage to integrate AddTywavesAnnotation phase (run before Convert phase only if withDebug is true)

Point 2, however, raises some doubts for me. It explores a Chisel circuit as it is done in Converter.convert, so there is a redundancy of code. I know, that, in general, annotations (such as dontTouch) are generated inside the builder context by the execution of the scala meta-program. However, if I were to let the user annotate every single variable/module this would become a long, repetitive, error-prone process. Consequently, I was wondering if I could create something alternative like binding a whole module and recursively annotating every hardware component in it. This I'm pretty sure is possible for IO ports but not for inner wires, registers, and modules.

rameloni commented 4 months ago

Update of 21-04-2024

I added annotation support to:

However, for memories the annotation of aggregates (Vecs, Bundles and user defined) will work only if the memory is effectively used. This means that, in the following example, annotations for the fields a and b of MyBundle are generated only when withConnection is true.

class TopCircuitSyncMem(withConnection: Boolean /* If true connect memPort */ ) extends Module {
  class MyBundle { val a = UInt(8.W); val b = SInt(8.W) }
  val gen = new MyBundle
  val mem = SyncReadMem(4, gen)
  if (withConnection) {
    val idx = IO(Input(UInt(2.W)))
    val in = IO(Input(gen))
    val out = IO(Output(gen))
    mem.write(idx, in)
    out := mem.read(idx)
  }
}

This would make sense to me since the mem is not instantiated if unused. However, I am unsure about that, since the annotation has MPORT.a and MPORT.b as targets rather than the expected mem.a and mem.b as targets.

I reported here the outputs: https://github.com/rameloni/chisel/blob/ff1de98fce44950d137dacc156da85dba8d3bddd/src/test/scala/circtTests/tywavesTests/memTests/README.md#syncreadmem

rameloni commented 4 months ago

Update of 22-04-2024

I would like to create the type annotation for parametric and parametrized modules in the following way:

class CircuitWithParam(n: Int, c: String)
   extends Module
class CircuitWithParam(val n: Int, val c: String)
   extends Module

class CircuitParametric[T] extends Module
{
  "class":"chisel3.tywaves.TywavesAnnotation",
  "target":"~CircuitWithParam|CircuitWithParam",
  "typeName":"CircuitWithParam(2, "Hello world!")"
}

Or using maps:

{
  "class":"chisel3.tywaves.TywavesAnnotation",
  "target":"~CircuitWithParam|CircuitWithParam",
  "typeName":"CircuitWithParam(n, c),
  "params":{
      "n":"2",
      "c":"Hello world!"
  }
}

While for parametric something similar:

{
  "class":"chisel3.tywaves.TywavesAnnotation",
  "target":"~CircuitParametric|CircuitParametric",
  "typeName":"CircuitParametric[Int]
}

Support for modules with parameters

I managed to get good results for getting values, names and types of field parameters. I am now able to retrieve the fields of any given scala class (including modules, bundles etc...) and filter the ones of the constructor only. In addition, I can also get recursive fields when a field is of a complex type.

I created a method getConstructorParams(target: Any): Seq(ClassParam) to do that, where ClassParam is a case class that I use to encode the parameters of a given class.

In the following example, I'm able to access any val (public, protected and private):

class Base(val a: Int, c: Float)
class A(private val a: Int, val x: String, val base: Base) { val c = 10 }
class B(protected val aClass: A) { val c = 10 }

val b = new B(new A(1, "ciao", new Base(3, 1.1f)))

println(getConstructorParams(b)) // This return a: case class ClassParam(name: String, typeName: String, value: Option[String])

This example would emit:

ClassParam("aClass", "A", Some("A(a: 1, x: ciao, base: Base(a: 3, c))")))

NOTE: it is worth to notice that seems that scala reflection cannot be used to access actual values of parameters that are not val or var. This is something, that I think it's not really a problem: if user likes to have also the value of a parameter of a module they should declare it as a val otherwise they can see only the type and the name.

So far I've tested it with generic scala classes. I still need to create proper tests for parametric chisel constructs, but they would work similarly so I don't think I will have problems.

Support for paramteric modules

I think I can exploit scala reflection to get information also for Parametric classes.

jackkoenig commented 4 months ago

@rameloni You're doing some awesome work here. You might be at a good point to start looking into how this information should be consumed by firtool. We don't want to support annotations long term (they were the way we extended the Scala FIRRTL Compiler, but firtool doesn't have the same flexibility since the annotations have to be explicitly handled by the firtool codebase), so we should discuss how this information may be best communicated from Chisel to firtool, perhaps via the FIRRTL spec. I am not saying you shouldn't use annotations at the moment, but we should think about what representation the maintainers of firtool would prefer.

Related to that, I'm curious how this information should be represented within firtool across lowering. That's something I don't know much about so perhaps we should try to schedule time in the CIRCT meeting to discuss, or perhaps @seldridge or @fabianschuiki may have some ideas to share here.

rameloni commented 4 months ago

Thank you very much @jackkoenig. Yes, I think I now have enough support for a great part of the chisel constructs to start looking into the next step. Of course, there are other things to finish with annotations, but I guess I can eventually fix them meanwhile I'll be working on firtool.

I'm using annotations only in the last step of my implementation, all the other steps are independent from the annotation system. I decided to use the annotation system since it can associate arbitrary metadata to any firrtl target (solving the ID issue of my demo). In other words, I found it a good and easy way to systematically get a 1-to-1 mapping from chisel to firrtl.

I didn't look yet carefully into firtool since I was trying to implement the "parameter annotation for scala classes", I think I got a nice result about that. I'm also able to access names, types and values of a specific field (val and var) of any class, although I restricted it to the constructor only and I also need to add proper tests for Modules and Bundles with parameters. I'll make an updated post later today (I think it's a good way to post updates about the features I'm implementing).

fabianschuiki commented 4 months ago

This is really nice! 🥳 I agree with @jackkoenig that using annotations is good to get things rolling, but we'll have to find a more permanent solution later. Firtool internally uses its Debug dialect to track information through the pipeline. It currently uses the FIRRTL ports and types to conjure up these trackers.

Ideally, with your annotations @rameloni, we'd be able to generate these trackers directly from the annotations. In the long run, we may want to extend the FIRRTL spec to add statements that can annotate debug information as we need them. We can prototype a lot of this with intrinsics, while we try to figure out how things should work.

One cool first thing to try would be to make the Chisel compiler plugin that opportunistically annotates val names onto expressions actually create a debug variable intrinsic (which doesn't exist yet) for every val. That would make all vals show up in the waveform viewer, regardless of what happens in the Verilog. Then there's the whole hierarchy and call stack that we could try to annotate. Maybe mirroring the debug dialect ops in FIRRTL intrinsics is sufficient to add Chisel-level type and hierarchy info to the output.

rameloni commented 4 months ago

@fabianschuiki I managed to associate my annotations with the Firrtl dialect and process them MaterializeDebugInfo through the addAnnotation function in LowerAnnotations pass. Now, I should be able to include them into the debug dialect and access them from an emitter similarly to EmitHgldd. To do so, I've been thinking of adding an optional field in the debug dialect operations to contain that information.

At the moment, I thought to try to get it working through annotations because it wouldn't require to update/add new things on chisel side the code and I wanted to understand a bit more how firtool works. Regarding the intrinsics, I'll postpone their usage if I get it fully working with the annotations, otherwise I'll stop implementing it through annotations and I'll move to intrinsics.

And thank you for the help and recommendations!

fabianschuiki commented 4 months ago

That sounds very exciting! What kind of additional information do you want to attach to the debug operations? You should be able to do so without changing the debug dialect directly, by just adding them as attributes when you create the operation itself. That might get you pretty far.

rameloni commented 4 months ago

Yes, with "adding optional field" I meant an attribute through the table gen. I thought to attach what I have in the annotations so far: the chisel type and the list parameters of that type constructor (which also define the "type").

However, I may process the annotations directly into the emitter without passing through the MaterializeDebugInfo and without adding any attribute to the debug dialect. This is a last minute idea though 😅 maybe an attribute in the debug dialect is not needed.

fabianschuiki commented 4 months ago

Yeah you can also add attributes to ops that are not part of the debug dialect *.td file. That's very useful for experimenting and getting things up and running, before you decide exactly what to do.

If the Chisel type is a struct or array, you probably want to create many debug dialect ops for it. Basically, disassemble the FIRRTL value and reassemble it based on your type using dbg.array, dbg.struct, and dbg.variable ops. One of the key things the debug dialect wants to do is track how things like struct fields or class members are modified and transformed through the compilation pipeline. This is done by taking all struct/array types apart into separate %N values in the IR, and then re-assembling the structs and arrays using debug dialect op. That allows the compiler to do whatever it wants with the values in order to optimize the compilation, while the debug dialect can still tell you how to assemble the original Chisel type.

Do you have a few concrete examples of how that type information looks like?

rameloni commented 4 months ago

Yes, I've seen that, I've already played a bit with that. I'll try to get an emitter tomorrow with a file format compatible with the viewer (the one I generated through the demo), so I think I'll fix some technical issues of the demo and then I can redefine the file format with a better and more robust version (hopefully from Monday).

rameloni commented 4 months ago

If the Chisel type is a struct or array, you probably want to create many debug dialect ops for it. Basically, disassemble the FIRRTL value and reassemble it based on your type using dbg.array, dbg.struct, and dbg.variable ops. One of the key things the debug dialect wants to do is track how things like struct fields or class members are modified and transformed through the compilation pipeline. This is done by taking all struct/array types apart into separate %N values in the IR, and then re-assembling the structs and arrays using debug dialect op. That allows the compiler to do whatever it wants with the values in order to optimize the compilation, while the debug dialect can still tell you how to assemble the original Chisel type.

Oh yes, I see why debug dialect is important for this aspect, it may justify the choice of adding an attribute instead of propagating the annotations attached to firrtl to the emitter.

Do you have a few concrete examples of how that type information looks like?

I have some examples of how this type information is represented in firrtl annotations. I think an example with bundles and vecs may be enough to cover almost all cases (I tried to compact the output of firrtl):

// A user defined bundle
class MyBundle[B <: Data](val x: B, val w: Int) extends Bundle {
    val innerX = UInt(w.W)
}

// A nested bundle
class MyBundleNested(val size: Int) extends Bundle {
    val inner1 = SInt(7.W)
    val inner2 = new MyBundle(Bool(), size)
    val inner3 = Vec(2, new Bundle {val y = Bool()})// Vector of anonymous bundles
}

class TopCircuit[T <: Data] extends RawModule {
    val aIn = IO(Input(new Bundle {}))
    val bIn = IO(Input(new MyBundle(UInt(8.W), 2)))
    val vIn = IO(Input(Vec(4, UInt(8.W))))

    val nested = Wire(new MyBundleNested(4))
    val nestedOut = IO(Output(new MyBundleNested(4)))

    // Connections
    nested.inner1 := vIn(0).asSInt
    nested.inner2 := bIn

    nestedOut <> nested

}
FIRRTL version 4.0.0
circuit TopCircuit :%[[
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit", 
    "typeName":"TopCircuit"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>aIn", 
    "typeName":"IO[AnonymousBundle]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>bIn.innerX", 
    "typeName":"IO[UInt<2>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>bIn.x", 
    "typeName":"IO[UInt<8>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>bIn", 
    "typeName":"IO[MyBundle]",
    "params":[
      { "name":"x", "typeName":"B", "value":"IO[UInt<8>]" },
      { "name":"w", "typeName":"Int", "value":"2" }
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>vIn[0]",
    "typeName":"IO[UInt<8>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>vIn",
    "typeName":"IO[UInt<8>[4]]",
    "params":[
      { "name":"gen", "typeName":"=> T"},
      { "name":"length", "typeName":"Int" }
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut.inner3[0].y",
    "typeName":"IO[Bool]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut.inner3[0]",
    "typeName":"IO[AnonymousBundle]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation",  "target":"~TopCircuit|TopCircuit>nestedOut.inner3",
    "typeName":"IO[AnonymousBundle[2]]",
    "params":[
      { "name":"gen", "typeName":"=> T" },
      { "name":"length", "typeName":"Int" }
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut.inner2.innerX",
    "typeName":"IO[UInt<4>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut.inner2.x",
    "typeName":"IO[Bool]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut.inner2",
    "typeName":"IO[MyBundle]",
    "params":[
      { "name":"x", "typeName":"B", "value":"IO[Bool]" },
      { "name":"w", "typeName":"Int", "value":"4" }
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut.inner1",
    "typeName":"IO[SInt<7>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nestedOut",
    "typeName":"IO[MyBundleNested]",
    "params":[
      { "name":"size", "typeName":"Int", "value":"4" }
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner3[0].y",
    "typeName":"Wire[Bool]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner3[0]",
    "typeName":"Wire[AnonymousBundle]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner3",
    "typeName":"Wire[AnonymousBundle[2]]",
    "params":[
      { "name":"gen", "typeName":"=> T"},
      { "name":"length", "typeName":"Int"}
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner2.innerX",
    "typeName":"Wire[UInt<4>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner2.x",
    "typeName":"Wire[Bool]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner2",
    "typeName":"Wire[MyBundle]",
    "params":[
      { "name":"x", "typeName":"B", "value":"Wire[Bool]" },
      { "name":"w", "typeName":"Int", "value":"4" }
    ]
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested.inner1",
    "typeName":"Wire[SInt<7>]"
  },
  {
    "class":"chisel3.tywaves.TywavesAnnotation", "target":"~TopCircuit|TopCircuit>nested",
    "typeName":"Wire[MyBundleNested]",
    "params":[
      { "name":"size", "typeName":"Int", "value":"4" }
    ]
  }
]]
  public module TopCircuit :
    input aIn : { }
    input bIn : { x : UInt<8>, innerX : UInt<2>}
    input vIn : UInt<8>[4]
    output nestedOut : { inner1 : SInt<7>, inner2 : { x : UInt<1>, innerX : UInt<4>}}

    wire nested : { inner1 : SInt<7>, inner2 : { x : UInt<1>, innerX : UInt<4>}}
    node _nested_inner1_T = asSInt(vIn[0])
    connect nested.inner1, _nested_inner1_T
    connect nested.inner2, bIn
    connect nestedOut, nested

I have other examples here:

rameloni commented 4 months ago

I moved the conversation about the part related to firtool here: https://github.com/llvm/circt/issues/6983

I thought it was better since I'm working on circt for this part.

rameloni commented 2 months ago

@jackkoenig is there any diagram about chiselsim pipeline? I may need for my thesis, but I only found the one in the chiselbook which is outdated since it uses the SFC and not firtool. I could always create one by myself, but I was wondering if there's an official one that I can use. Thanks ;)