Open rameloni opened 4 months ago
These tables summarize which chisel constructs are currently supported and related commit.
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 |
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: |
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 |
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 |
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 |
I have already done some work on that: https://github.com/rameloni/chisel/commit/65a47f3c51be2aaba10a3c298aae4b39575f0800
So far I:
TywavesAnnotation
(firrtl) case class to represent the annotationChiselAnnotation
s for Chisel circuit: it parses a chisel circuit, extracts the necessary information from each component, and annotates each FIRRTL targetAddTywavesAnnotations
phase to add the TywavesAnnotation to the elaborated Chisel circuitChiselStage
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.
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
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]
}
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
orvar
. 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 aval
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.
I 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. 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).
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 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!
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. 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.
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?
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).
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
, anddbg.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:
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.
@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.