summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/util/BlackBoxUtils.scala5
-rw-r--r--src/main/scala/chisel3/util/ExtModuleUtils.scala61
-rw-r--r--src/test/scala/chiselTests/ExtModuleImpl.scala141
3 files changed, 207 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/util/BlackBoxUtils.scala b/src/main/scala/chisel3/util/BlackBoxUtils.scala
index 74d99ff8..21bd4dfa 100644
--- a/src/main/scala/chisel3/util/BlackBoxUtils.scala
+++ b/src/main/scala/chisel3/util/BlackBoxUtils.scala
@@ -32,6 +32,11 @@ trait HasBlackBoxResource extends BlackBox {
trait HasBlackBoxInline extends BlackBox {
self: BlackBox =>
+ /** Creates a black box verilog file, from the contents of a local string
+ *
+ * @param blackBoxName The black box module name, to create filename
+ * @param blackBoxInline The black box contents
+ */
def setInline(blackBoxName: String, blackBoxInline: String): Unit = {
val anno = new ChiselAnnotation with RunFirrtlTransform {
def toFirrtl = BlackBoxInlineAnno(self.toNamed, blackBoxName, blackBoxInline)
diff --git a/src/main/scala/chisel3/util/ExtModuleUtils.scala b/src/main/scala/chisel3/util/ExtModuleUtils.scala
new file mode 100644
index 00000000..831639be
--- /dev/null
+++ b/src/main/scala/chisel3/util/ExtModuleUtils.scala
@@ -0,0 +1,61 @@
+// See LICENSE for license details.
+
+package chisel3.util
+
+import chisel3.experimental.{ChiselAnnotation, ExtModule, RunFirrtlTransform}
+import firrtl.transforms.{BlackBoxPathAnno, BlackBoxResourceAnno, BlackBoxInlineAnno, BlackBoxSourceHelper}
+
+trait HasExtModuleResource extends ExtModule {
+ self: ExtModule =>
+
+ /** Copies a resource file to the target directory
+ *
+ * Resource files are located in project_root/src/main/resources/.
+ * Example of adding the resource file project_root/src/main/resources/blackbox.v:
+ * {{{
+ * addResource("/blackbox.v")
+ * }}}
+ */
+ def addResource(blackBoxResource: String): Unit = {
+ val anno = new ChiselAnnotation with RunFirrtlTransform {
+ def toFirrtl = BlackBoxResourceAnno(self.toNamed, blackBoxResource)
+ def transformClass = classOf[BlackBoxSourceHelper]
+ }
+ chisel3.experimental.annotate(anno)
+ }
+}
+
+trait HasExtModuleInline extends ExtModule {
+ self: ExtModule =>
+
+ /** Creates a black box verilog file, from the contents of a local string
+ *
+ * @param blackBoxName The black box module name, to create filename
+ * @param blackBoxInline The black box contents
+ */
+ def setInline(blackBoxName: String, blackBoxInline: String): Unit = {
+ val anno = new ChiselAnnotation with RunFirrtlTransform {
+ def toFirrtl = BlackBoxInlineAnno(self.toNamed, blackBoxName, blackBoxInline)
+ def transformClass = classOf[BlackBoxSourceHelper]
+ }
+ chisel3.experimental.annotate(anno)
+ }
+}
+
+trait HasExtModulePath extends ExtModule {
+ self: ExtModule =>
+
+ /** Copies a file to the target directory
+ *
+ * This works with absolute and relative paths. Relative paths are relative
+ * to the current working directory, which is generally not the same as the
+ * target directory.
+ */
+ def addPath(blackBoxPath: String): Unit = {
+ val anno = new ChiselAnnotation with RunFirrtlTransform {
+ def toFirrtl = BlackBoxPathAnno(self.toNamed, blackBoxPath)
+ def transformClass = classOf[BlackBoxSourceHelper]
+ }
+ chisel3.experimental.annotate(anno)
+ }
+}
diff --git a/src/test/scala/chiselTests/ExtModuleImpl.scala b/src/test/scala/chiselTests/ExtModuleImpl.scala
new file mode 100644
index 00000000..f71a1335
--- /dev/null
+++ b/src/test/scala/chiselTests/ExtModuleImpl.scala
@@ -0,0 +1,141 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import java.io.File
+
+import chisel3._
+import chisel3.experimental.ExtModule
+import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
+import chisel3.util.{HasExtModuleInline, HasExtModulePath, HasExtModuleResource}
+import firrtl.FirrtlExecutionSuccess
+import firrtl.options.TargetDirAnnotation
+import firrtl.stage.FirrtlCircuitAnnotation
+import org.scalacheck.Test.Failed
+import org.scalatest.{FreeSpec, Matchers, Succeeded}
+
+//scalastyle:off magic.number
+
+class ExtModuleAdd(n: Int) extends ExtModule with HasExtModuleInline {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ //scalastyle:off regex
+ setInline("ExtModuleAdd.v", s"""
+ |module ExtModuleAdd(
+ | input [15:0] in,
+ | output [15:0] out
+ |);
+ | assign out = in + $n;
+ |endmodule
+ """.stripMargin)
+}
+
+class UsesExtModuleAddViaInline extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ val blackBoxAdd = Module(new ExtModuleAdd(5))
+ blackBoxAdd.io.in := io.in
+ io.out := blackBoxAdd.io.out
+}
+
+class ExtModuleMinus extends ExtModule with HasExtModuleResource {
+ val io = IO(new Bundle {
+ val in1 = Input(UInt(16.W))
+ val in2 = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+ addResource("/chisel3/BlackBoxTest.v")
+}
+
+class ExtModuleMinusPath extends ExtModule with HasExtModulePath {
+ val io = IO(new Bundle {
+ val in1 = Input(UInt(16.W))
+ val in2 = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+ addPath(
+ new File("src/test/resources/chisel3/BlackBoxTest.v").getCanonicalPath
+ )
+}
+
+class UsesExtModuleMinusViaResource extends Module {
+ val io = IO(new Bundle {
+ val in1 = Input(UInt(16.W))
+ val in2 = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ val mod0 = Module(new ExtModuleMinus)
+
+ mod0.io.in1 := io.in1
+ mod0.io.in2 := io.in2
+ io.out := mod0.io.out
+}
+
+class UsesExtModuleMinusViaPath extends Module {
+ val io = IO(new Bundle {
+ val in1 = Input(UInt(16.W))
+ val in2 = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ val mod0 = Module(new ExtModuleMinusPath)
+
+ mod0.io.in1 := io.in1
+ mod0.io.in2 := io.in2
+ io.out := mod0.io.out
+}
+
+class ExtModuleImplSpec extends FreeSpec with Matchers {
+ "ExtModule can have verilator source implementation" - {
+
+ "Implementations can be contained in-line" in {
+ val targetDir = "test_run_dir/extmodule-inline"
+
+ val annotations = Seq(
+ TargetDirAnnotation(targetDir),
+ ChiselGeneratorAnnotation(() => new UsesExtModuleAddViaInline)
+ )
+ val newAnnotations = (new ChiselStage).transform(annotations)
+
+ newAnnotations.exists(_.isInstanceOf[FirrtlCircuitAnnotation]) should be (true)
+ val verilogOutput = new File(targetDir, "ExtModuleAdd.v")
+ verilogOutput.exists() should be(true)
+ verilogOutput.delete()
+ }
+
+ "Implementations can be contained in resource files" in {
+ val targetDir = "test_run_dir/extmodule-resource"
+ val annotations = Seq(
+ TargetDirAnnotation(targetDir),
+ ChiselGeneratorAnnotation(() => new UsesExtModuleMinusViaResource)
+ )
+ val newAnnotations = (new ChiselStage).transform(annotations)
+
+ newAnnotations.exists(_.isInstanceOf[FirrtlCircuitAnnotation]) should be (true)
+ val verilogOutput = new File(targetDir, "BlackBoxTest.v")
+ verilogOutput.exists() should be(true)
+ verilogOutput.delete()
+ }
+
+ "Implementations can be contained in arbitrary files" in {
+ val targetDir = "test_run_dir/extmodule-path"
+ val annotations = Seq(
+ TargetDirAnnotation(targetDir),
+ ChiselGeneratorAnnotation(() => new UsesExtModuleMinusViaPath)
+ )
+ val newAnnotations = (new ChiselStage).transform(annotations)
+
+ newAnnotations.exists(_.isInstanceOf[FirrtlCircuitAnnotation]) should be (true)
+ val verilogOutput = new File(targetDir, "BlackBoxTest.v")
+ verilogOutput.exists() should be(true)
+ verilogOutput.delete()
+ }
+ }
+}