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

ExtModule's lacked support built in support for providing #1154

Merged
merged 7 commits into from
Oct 13, 2020
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),
chick marked this conversation as resolved.
Show resolved Hide resolved
)
val newAnnotations = (new ChiselStage).run(annotations)
Copy link
Member

Choose a reason for hiding this comment

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

It would be better to use the transform or execute methods instead of run. The latter is what the user is supposed to implement, while the former two are running all the pre- and post-run steps.

Ditto for other usages below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to use .transform


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),
chick marked this conversation as resolved.
Show resolved Hide resolved
)
val newAnnotations = (new ChiselStage).run(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),
chick marked this conversation as resolved.
Show resolved Hide resolved
)
val newAnnotations = (new ChiselStage).run(annotations)

newAnnotations.exists(_.isInstanceOf[FirrtlCircuitAnnotation]) should be (true)
val verilogOutput = new File(targetDir, "BlackBoxTest.v")
verilogOutput.exists() should be(true)
verilogOutput.delete()
}
}
}