-
Notifications
You must be signed in to change notification settings - Fork 577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pass Chisel information to firtool to generate debug information for the Tywaves project #4015
Comments
Tracking supported chisel constructs emitted in FIRRTL annotationsThese tables summarize which chisel constructs are currently supported and related commit.
Module types
Chisel Data types
Hardware bindings
Memories
Others
|
Update of 19-04-2024I have already done some work on that: rameloni@65a47f3 So far I:
Point 2, however, raises some doubts for me. It explores a Chisel circuit as it is done in |
Update of 21-04-2024I 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 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 I reported here the outputs: https://github.com/rameloni/chisel/blob/ff1de98fce44950d137dacc156da85dba8d3bddd/src/test/scala/circtTests/tywavesTests/memTests/README.md#syncreadmem |
Update of 22-04-2024I 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
Or using maps:
While for parametric something similar:
Support for modules with parametersI 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 In the following example, I'm able to access any 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:
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 modulesI think I can exploit scala reflection to get information also for Parametric classes. |
@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. |
Thank you very much @jackkoenig. I'm using annotations only in the last step of my implementation, all the other steps are independent from the annotation system. 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 ( |
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. |
@fabianschuiki I managed to associate my annotations with the Firrtl dialect and process them 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. And thank you for the help and recommendations! |
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. |
Yes, with "adding optional field" I meant an attribute through the table gen. However, I may process the annotations directly into the emitter without passing through the |
Yeah you can also add attributes to ops that are not part of the debug dialect 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 Do you have a few concrete examples of how that type information looks like? |
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). |
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.
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
}
I have other examples here:
|
I moved the conversation about the part related to firtool here: llvm/circt#6983 I thought it was better since I'm working on circt for this part. |
@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 ;) |
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:
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:
class MyModule[T<:Data](gen: T, n: T) extends RawModule
). This last is more challenging though.ChiselStage.emitSystemVerilog)
for example.The text was updated successfully, but these errors were encountered: