Skip to content
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

Merged
merged 5 commits into from
Jul 11, 2024

Conversation

uenoku
Copy link
Contributor

@uenoku uenoku commented Jun 10, 2024

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

  • Did you add Scaladoc to every public function/method?
  • Did you add at least one test demonstrating the PR?
  • Did you delete any extraneous printlns/debugging code?
  • Did you specify the type of improvement?
  • Did you add appropriate documentation in docs/src?
  • Did you request a desired merge strategy?
  • Did you add text to be included in the Release Notes for this change?

Type of Improvement

  • Feature (or new API)

Desired Merge Strategy

  • Squash: The PR will be squashed and merged (choose this if you have no preference).

Release Notes

Reviewer Checklist (only modified by reviewer)

  • Did you add the appropriate labels? (Select the most appropriate one based on the "Type of Improvement")
  • Did you mark the proper milestone (Bug fix: 3.6.x, 5.x, or 6.x depending on impact, API modification or big change: 7.0)?
  • Did you review?
  • Did you check whether all relevant Contributor checkboxes have been checked?
  • Did you do one of the following when ready to merge:
    • Squash: You/ the contributor Enable auto-merge (squash), clean up the commit message, and label with Please Merge.
    • Merge: Ensure that contributor has cleaned up their commit history, then merge with Create a merge commit.

@uenoku uenoku added the Feature New feature, will be included in release notes label Jun 10, 2024
@uenoku uenoku requested review from jackkoenig and debs-sifive June 10, 2024 07:10
| std::cout << "hello from c++\\n";
|}
|
|extern "C" void add(int lhs, int rhs, int* result)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment for link.

Copy link
Member

@sequencer sequencer left a 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 = {
Copy link
Member

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?

Copy link
Contributor Author

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)
Copy link
Member

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?

Copy link
Contributor Author

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 = {
Copy link
Member

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.

Copy link
Contributor Author

@uenoku uenoku Jun 13, 2024

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

@uenoku uenoku Jun 17, 2024

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 :)

Copy link
Member

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

@sequencer
Copy link
Member

Maybe RawUnclockedVoidFunctionCall is missing?

@sequencer
Copy link
Member

Two questions:

  • How to add a DPI function which is called at initial?(maybe need some preset flag to true.B as guard of this DPI, then configured it to false after initial)
  • How to export DPI functions? This is not designed for driver, but can be used for logging.

@uenoku
Copy link
Contributor Author

uenoku commented Jun 19, 2024

Maybe RawUnclockedVoidFunctionCall is missing?

It's intentional since it's illegal to call void-function on non-procedural region.

How to add a DPI function which is called at initial?(maybe need some preset flag to true.B as guard of this DPI, then configured it to false after initial)

Good point. This is not currently supported. The reason why we cannot simply add sort of initial flag to DPI call op is that it will create dependency between two values in the same timing, e.g:

wire w;
node b = dpi_call_initial<func>(w);
node a = dpi_call_initial<func>(b);
w <= a

--> 

initial begin
   a = func(b);
   b = func(a);
end

or 

initial begin
   b = func(a);
   a = func(b);
end

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.

How to export DPI functions? This is not designed for driver, but can be used for logging.

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 .

@sequencer
Copy link
Member

Another nit pick: when passing Reg to DPI, it will trigger the comb logic cycle error.

Copy link
Member

@sequencer sequencer left a 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

src/main/scala/chisel3/util/circt/DPI.scala Outdated Show resolved Hide resolved
src/main/scala/chisel3/util/circt/DPI.scala Outdated Show resolved Hide resolved
src/main/scala/chisel3/util/circt/DPI.scala Outdated Show resolved Hide resolved
@uenoku uenoku changed the base branch from main to ci/ci-circt-nightly July 5, 2024 07:39
@uenoku uenoku marked this pull request as ready for review July 5, 2024 07:39
@uenoku
Copy link
Contributor Author

uenoku commented Jul 5, 2024

Sorry for delay. It's ready for review now.

@uenoku uenoku changed the title Add a raw API for DPI intrinsics Add DPI intrinsics and API Jul 8, 2024
@uenoku uenoku force-pushed the dev/hidetou/dpi branch from f065389 to cf4b0d1 Compare July 8, 2024 08:50
Comment on lines +98 to +100
Hello()
val result_clocked = AddClocked(io.a, io.b)
val result_unclocked = AddUnclocked(io.a, io.b)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment for link

@uenoku uenoku force-pushed the dev/hidetou/dpi branch from cf4b0d1 to af89a23 Compare July 8, 2024 11:21
@jackkoenig jackkoenig added this to the 7.0 milestone Jul 8, 2024
@github-actions github-actions bot force-pushed the ci/ci-circt-nightly branch from 1f3caf4 to cc782e9 Compare July 9, 2024 11:05
Copy link
Contributor

@fabianschuiki fabianschuiki left a 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!

src/test/scala/chiselTests/DPISpec.scala Outdated Show resolved Hide resolved
@jackkoenig jackkoenig force-pushed the ci/ci-circt-nightly branch from cc782e9 to 2a8affd Compare July 9, 2024 17:41
Comment on lines 65 to 72
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)
Copy link
Contributor

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?

Copy link
Member

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.

Copy link
Contributor

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!

@github-actions github-actions bot force-pushed the ci/ci-circt-nightly branch 2 times, most recently from ac00864 to 4a00443 Compare July 11, 2024 11:05
Copy link
Contributor

@jackkoenig jackkoenig left a 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")
Copy link
Contributor

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.

@jackkoenig jackkoenig merged commit bba4610 into chipsalliance:ci/ci-circt-nightly Jul 11, 2024
13 checks passed
@dtzSiFive
Copy link
Member

Great work! 🚀

@uenoku
Copy link
Contributor Author

uenoku commented Jul 11, 2024

Thank you for review!

github-actions bot pushed a commit that referenced this pull request Jul 12, 2024
chiselbot pushed a commit that referenced this pull request Jul 13, 2024
@sequencer
Copy link
Member

sequencer commented Jul 18, 2024

For those who come into this PR, and interested in the usage of Chisel DPI, here is a concrete opensource example of using DPIIntrinsic + verilator:

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New feature, will be included in release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants