-
Notifications
You must be signed in to change notification settings - Fork 615
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
Add DPI intrinsics and API #4158
Add DPI intrinsics and API #4158
Conversation
| std::cout << "hello from c++\\n"; | ||
|} | ||
| | ||
|extern "C" void add(int lhs, int rhs, int* result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment for link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just small thoughts.
* val a = RawClockedNonVoidFunctionCall("dpi_func_foo", UInt(1.W), clock, enable, b, c) | ||
* }}} | ||
*/ | ||
def apply[T <: Data](functionName: String, ret: => T)(clock: Clock, enable: Bool, data: Data*): Data = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the return type being a aggregate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can return passive aggregate. I'll add a similar document but here is ABI for DPI: llvm/circt#7163
val result = RawClockedNonVoidFunctionCall("add", UInt(32.W))(clock, true.B, io.a, io.b) | ||
|
||
// A function that allocates a state and returns a pointer. | ||
val counter = RawClockedNonVoidFunctionCall("create_counter", UInt(64.W))(clock, reset.asBool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally in SystemVerilog, if put multiple RawClockedNonVoidFunctionCall
in an always block, they will be executed in order. This is be used to schedule the order of different DPI calls with dependencies, e.g. peek valid
signal and poke the ready
signal for handshake. It seems that we need to merge two DPIs together to achieve this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we need to merge two DPIs together to achieve this?
Exactly, that's recommended way to model DPI dependency. It's extremely hard and breaking change to represent dependency within always clock with the current FIRRTL representation.
* val a = RawUnlockedNonVoidFunctionCall("dpi_func_foo", UInt(1.W), enable, b, c) | ||
* }}} | ||
*/ | ||
def apply[T <: Data](functionName: String, ret: => T)(enable: Bool, data: Data*): Data = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have been thinking: how to pass a string to DPI in Chisel, as well as Plusarg, maybe we also need a StringLit
type in Chisel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. We'd like to pass and create a string, open array or chandle as well (chandle can be representable with UInt<64> though). My plan is to introduce "intrinsic/foreign type" concept so they can be created by intrinsics and that's orthogonal proposal to DPI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think PlusArg already have intrinsic so I guess we can use that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we may need a Chisel String data type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think creating Chisel/FIRRTL String type is a right way but it will require more design discussion and lots of implementation. I guess we can use Vec<UInt<8>, n>
as a way to represent string for now :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mind blowing. But yes, we can do it
Maybe |
Two questions:
|
It's intentional since it's illegal to call void-function on non-procedural region.
Good point. This is not currently supported. The reason why we cannot simply add sort of
I think we can restrict operands of dpi_call_initial op to be constant types but there are few other representation so I'm still iterating on the IR design.
This is out-of-scope now since currently FIRRTL has nothing to export :) I think we first need to introduce FIRRTL functions as first class citizen. CIRCT SV dialect recently got function support but for FIRRTL side it's still in design phase . |
Another nit pick: when passing Reg to DPI, it will trigger the comb logic cycle error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nit on the return tpe
Sorry for delay. It's ready for review now. |
Hello() | ||
val result_clocked = AddClocked(io.a, io.b) | ||
val result_unclocked = AddUnclocked(io.a, io.b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment for link
1f3caf4
to
cc782e9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very exciting to see this work!
cc782e9
to
2a8affd
Compare
object Hello extends DPIClockedVoidFunctionImport { | ||
val functionName = "hello" | ||
final def apply() = super.call() | ||
} | ||
|
||
object AddClocked extends DPINonVoidFunctionImport[UInt] { | ||
override val functionName = "add" | ||
val ret = UInt(32.W) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm of two minds of this API here. It's common in Chisel for user APIs to be inheritance based, but I don't think it's generally the best option. I'm not sure if I have a better idea though and I don't want to sandbag so maybe we just go with it and change it later if we need to. Any thoughts @seldridge?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some precedence for this kind of API for things like layers where you want to "declare" something and then refer to it multiple times. Using the object here achieves that (though I mentioned to @uenoku to self-type this with this: Singleton =>
to mandate an object). Also, this could be slightly cleaner as an abstract class
in order to avoid the copious overrides.
Let's try this and see where it bottoms out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me, thanks @seldridge!
ac00864
to
4a00443
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fantastic, thank you @uenoku!
} | ||
.result | ||
|
||
val outputFile = io.Source.fromFile("test_run_dir/simulator/DPIIntrinsic/workdir-verilator/simulation-log.txt") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we would be a little DRY-er on these paths, deriving them from values defined above, but I'm not gonna block this PR on that.
bba4610
into
chipsalliance:ci/ci-circt-nightly
Great work! 🚀 |
Thank you for review! |
For those who come into this PR, and interested in the usage of Chisel DPI, here is a concrete opensource example of using
then link the dpi w/ verilator, then you can drive the Verilog with your native language then. VCS should work as well, but due to the NDA limitation those cannot be opensourced. |
This PR adds DPI intrinsic support and API to define DPI functions declaratively. The test passes locally but requires a new version of firtool.
Contributor Checklist
docs/src
?Type of Improvement
Desired Merge Strategy
Release Notes
Reviewer Checklist (only modified by reviewer)
3.6.x
,5.x
, or6.x
depending on impact, API modification or big change:7.0
)?Enable auto-merge (squash)
, clean up the commit message, and label withPlease Merge
.Create a merge commit
.