Skip to content

Commit

Permalink
Add DPI API
Browse files Browse the repository at this point in the history
  • Loading branch information
uenoku committed Jul 8, 2024
1 parent 5b9301f commit f065389
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 26 deletions.
26 changes: 26 additions & 0 deletions src/main/scala/chisel3/util/circt/DPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,29 @@ object RawClockedVoidFunctionCall {
)
}
}

trait DPIFunctionDecl {
val functionName: String
val inputNames: Option[Seq[String]] = None
}

// Base trait for a clocked non-void function that returns `T`.
trait DPINonVoidFunctionDecl[T <: Data] extends DPIFunctionDecl {
val ret: T
val clocked: Boolean
val outputName: Option[String] = None
def callWithEnable(enable: Bool, data: Data*): T =
if (clocked) {
RawClockedNonVoidFunctionCall(functionName, ret, inputNames, outputName)(Module.clock, enable, data: _*)
} else {
RawUnclockedNonVoidFunctionCall(functionName, ret, inputNames, outputName)(enable, data: _*)
}
def call(data: Data*): T = callWithEnable(true.B, data: _*)
}

// Base trait for a clocked void function.
trait DPIClockedVoidFunctionDecl extends DPIFunctionDecl {
def callWithEnable(enable: Bool, data: Data*): Unit =
RawClockedVoidFunctionCall(functionName, inputNames)(Module.clock, enable, data: _*)
def call(data: Data*): Unit = callWithEnable(true.B, data: _*)
}
130 changes: 104 additions & 26 deletions src/test/scala/chiselTests/DPISpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,43 @@ import org.scalatest.matchers.should.Matchers.convertToAnyShouldWrapper
import chisel3.util.HasBlackBoxInline
import svsim._

class DPITest extends Module {
val dpiImpl = s"""
|#include <stdint.h>
|#include <iostream>
|
|extern "C" void hello()
|{
| std::cout << "hello from c++\\n";
|}
|
|extern "C" void add(int lhs, int rhs, int* result)
|{
| *result = lhs + rhs;
|}
private object EmitDPIImplementation {
def apply() = {
val dpiImpl = s"""
|#include <stdint.h>
|#include <iostream>
|
|extern "C" void hello()
|{
| std::cout << "hello from c++\\n";
|}
|
|extern "C" void add(int lhs, int rhs, int* result)
|{
| *result = lhs + rhs;
|}
""".stripMargin

class DummyDPI extends BlackBox with HasBlackBoxInline {
val io = IO(new Bundle {})
setInline("dpi.cc", dpiImpl)
setInline(s"$desiredName.sv", s"module $desiredName(); endmodule")
}
val dummy = Module(new DummyDPI)

}
}

class DPIIntrinsicTest extends Module {
val io = IO(new Bundle {
val a = Input(UInt(32.W))
val b = Input(UInt(32.W))
val add_clocked_result = Output(UInt(32.W))
val add_unclocked_result = Output(UInt(32.W))
})

EmitDPIImplementation()

// Void function
RawClockedVoidFunctionCall("hello")(clock, true.B)

Expand All @@ -44,25 +58,89 @@ class DPITest extends Module {
val result_unclocked =
RawUnclockedNonVoidFunctionCall("add", UInt(32.W), Some(Seq("lhs", "rhs")), Some("result"))(true.B, io.a, io.b)

class DummyDPI extends BlackBox with HasBlackBoxInline {
val io = IO(new Bundle {})
setInline("dpi.cc", dpiImpl)
setInline(s"$desiredName.sv", s"module $desiredName(); endmodule")
}
io.add_clocked_result := result_clocked
io.add_unclocked_result := result_unclocked
}

object Hello extends DPIClockedVoidFunctionDecl {
val functionName = "hello"
final def apply() = super.call()
}

object AddClocked extends DPINonVoidFunctionDecl[UInt] {
override val functionName = "add"
val ret = UInt(32.W)
val clocked = true
override val inputNames = Some(Seq("lhs", "rhs"))
override val outputName = Some("result")
final def apply(lhs: UInt, rhs: UInt): UInt = super.call(lhs, rhs)
}

val dummy = Module(new DummyDPI)
object AddUnclocked extends DPINonVoidFunctionDecl[UInt] {
override val functionName = "add"
val ret = UInt(32.W)
val clocked = false
override val inputNames = Some(Seq("lhs", "rhs"))
override val outputName = Some("result")
final def apply(lhs: UInt, rhs: UInt): UInt = super.call(lhs, rhs)
}

class DPIAPITest extends Module {
val io = IO(new Bundle {
val a = Input(UInt(32.W))
val b = Input(UInt(32.W))
val add_clocked_result = Output(UInt(32.W))
val add_unclocked_result = Output(UInt(32.W))
})

EmitDPIImplementation()

Hello()
val result_clocked = AddClocked(io.a, io.b)
val result_unclocked = AddUnclocked(io.a, io.b)

io.add_clocked_result := result_clocked
io.add_unclocked_result := result_unclocked
}

class DPISpec extends AnyFunSpec with Matchers {
describe("DPI intrinsic") {
it("runs DPI correctly") {
val simulator = new VerilatorSimulator("test_run_dir/simulator/DPISimulator")
describe("DPI") {
it("DPI intrinsics run correctly") {
val simulator = new VerilatorSimulator("test_run_dir/simulator/DPIIntrinsic")

simulator
.simulate(new DPIIntrinsicTest()) { module =>
import PeekPokeAPI._
val dpi = module.wrapped
dpi.reset.poke(true)
dpi.clock.step()

dpi.reset.poke(false)
dpi.io.a.poke(24.U)
dpi.io.b.poke(36.U)
dpi.io.add_unclocked_result.peek()
dpi.io.add_unclocked_result.expect(60)

dpi.clock.step()
dpi.io.a.poke(24.U)
dpi.io.b.poke(12.U)
dpi.io.add_clocked_result.peek()
dpi.io.add_clocked_result.expect(60)
dpi.io.add_unclocked_result.peek()
dpi.io.add_unclocked_result.expect(36)
}
.result

val outputFile = io.Source.fromFile("test_run_dir/simulator/DPIIntrinsic/workdir-verilator/simulation-log.txt")
val output = outputFile.mkString
outputFile.close()
output should include("hello from c++")
}
it("DPI API run correctly") {
val simulator = new VerilatorSimulator("test_run_dir/simulator/DPIAPI")

simulator
.simulate(new DPITest()) { module =>
.simulate(new DPIAPITest()) { module =>
import PeekPokeAPI._
val dpi = module.wrapped
dpi.reset.poke(true)
Expand All @@ -84,14 +162,14 @@ class DPISpec extends AnyFunSpec with Matchers {
}
.result

val outputFile = io.Source.fromFile("test_run_dir/simulator/DPISimulator/workdir-verilator/simulation-log.txt")
val outputFile = io.Source.fromFile("test_run_dir/simulator/DPIAPI/workdir-verilator/simulation-log.txt")
val output = outputFile.mkString
outputFile.close()
output should include("hello from c++")
}
it("emits DPI correctly") {
val verilog = ChiselStage.emitSystemVerilog(
new DPITest(),
new DPIIntrinsicTest(),
firtoolOpts = Array("--lowering-options=locationInfoStyle=none,disallowPortDeclSharing")
)
verilog should include("import \"DPI-C\" function void add(")
Expand Down

0 comments on commit f065389

Please sign in to comment.