Skip to content

Commit

Permalink
ExtModule's lacked support built in support for providing (#1154)
Browse files Browse the repository at this point in the history
* ExtModule's lacked support built in support for providing
the verilog source. This changes creates traits that
can be used with ExtModule to provide the support currently found in
BlackBox

- Add support for ExtModule helpers
  - HasExtModuleResource to use addResource
  - HasExtModuleInline to use setInline
  - HasExtModulePath to use addPath
- Add tests of the above support.
  - Note: These tests use Stage instead of Driver
- Added ScalaDoc for HasBlackBoxInline#setInline

* Fix the danged trailing commas.

* Change to use `.transform` as the correct API for `ChiselStage`
  • Loading branch information
chick authored Oct 13, 2020
1 parent 1b15dca commit fd92809
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/main/scala/chisel3/util/BlackBoxUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
61 changes: 61 additions & 0 deletions src/main/scala/chisel3/util/ExtModuleUtils.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}
141 changes: 141 additions & 0 deletions src/test/scala/chiselTests/ExtModuleImpl.scala
Original file line number Diff line number Diff line change
@@ -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()
}
}
}

0 comments on commit fd92809

Please sign in to comment.