summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala18
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Module.scala10
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala5
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala8
-rw-r--r--src/main/scala/chisel3/internal/firrtl/Emitter.scala24
-rw-r--r--src/main/scala/chisel3/package.scala24
-rw-r--r--src/test/resources/BlackBoxTest.v25
-rw-r--r--src/test/scala/chiselTests/BlackBox.scala49
8 files changed, 140 insertions, 23 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala
index 7fe429fa..85a57111 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala
@@ -3,11 +3,20 @@
package chisel3.core
import chisel3.internal.Builder.pushCommand
-import chisel3.internal.firrtl.{ModuleIO, DefInvalid}
+import chisel3.internal.firrtl._
+import chisel3.internal.throwException
import chisel3.internal.sourceinfo.SourceInfo
// TODO: remove this once we have CompileOptions threaded through the macro system.
import chisel3.core.ExplicitCompileOptions.NotStrict
+/** Parameters for BlackBoxes */
+sealed abstract class Param
+case class IntParam(value: BigInt) extends Param
+case class DoubleParam(value: Double) extends Param
+case class StringParam(value: String) extends Param
+/** Unquoted String */
+case class RawParam(value: String) extends Param
+
/** Defines a black box, which is a module that can be referenced from within
* Chisel, but is not defined in the emitted Verilog. Useful for connecting
* to RTL modules defined outside Chisel.
@@ -16,12 +25,9 @@ import chisel3.core.ExplicitCompileOptions.NotStrict
* {{{
* ... to be written once a spec is finalized ...
* }}}
+ * @note The parameters API is experimental and may change
*/
-// REVIEW TODO: make Verilog parameters part of the constructor interface?
-abstract class BlackBox extends Module {
- // Don't bother taking override_clock|reset, clock/reset locked out anyway
- // TODO: actually implement this.
- def setVerilogParameters(s: String): Unit = {}
+abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param]) extends Module {
// The body of a BlackBox is empty, the real logic happens in firrtl/Emitter.scala
// Bypass standard clock, reset, io port declaration by flattening io
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index ca391091..62b6d5ce 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -41,8 +41,16 @@ object Module {
sourceInfo.makeMessage(" See " + _))
}
Builder.currentModule = parent // Back to parent!
+
val ports = m.computePorts
- val component = Component(m, m.name, ports, m._commands)
+ // Blackbox inherits from Module so we have to match on it first TODO fix
+ val component = m match {
+ case bb: BlackBox =>
+ DefBlackBox(bb, bb.name, ports, bb.params)
+ case mod: Module =>
+ mod._commands.prepend(DefInvalid(childSourceInfo, mod.io.ref)) // init module outputs
+ DefModule(mod, mod.name, ports, mod._commands)
+ }
m._component = Some(component)
Builder.components += component
// Avoid referencing 'parent' in top module
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
index 028ce628..60ce6d5d 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
@@ -181,7 +181,10 @@ private[chisel3] object Builder {
// TODO(twigg): Ideally, binding checks and new bindings would all occur here
// However, rest of frontend can't support this yet.
def pushCommand[T <: Command](c: T): T = {
- forcedModule._commands += c
+ forcedModule match {
+ case _: BlackBox => throwException("Cannot add hardware to a BlackBox")
+ case m => m._commands += c
+ }
c
}
def pushOp[T <: Data](cmd: DefPrim[T]): T = {
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
index 0f866c27..17b869f2 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -215,8 +215,14 @@ case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command
case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command
-case class Component(id: Module, name: String, ports: Seq[Port], commands: Seq[Command]) extends Arg
case class Port(id: Data, dir: Direction)
case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command
+abstract class Component extends Arg {
+ def id: Module
+ def name: String
+ def ports: Seq[Port]
+}
+case class DefModule(id: Module, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component
+case class DefBlackBox(id: Module, name: String, ports: Seq[Port], params: Map[String, Param]) extends Component
case class Circuit(name: String, components: Seq[Component])
diff --git a/src/main/scala/chisel3/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
index 3fb18893..b8651828 100644
--- a/src/main/scala/chisel3/internal/firrtl/Emitter.scala
+++ b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
@@ -2,6 +2,7 @@
package chisel3.internal.firrtl
import chisel3._
+import chisel3.experimental._
import chisel3.internal.sourceinfo.{NoSourceInfo, SourceLine}
private[chisel3] object Emitter {
@@ -42,6 +43,16 @@ private class Emitter(circuit: Circuit) {
firrtlLine + e.sourceInfo.makeMessage(" " + _)
}
+ private def emitParam(name: String, p: Param): String = {
+ val str = p match {
+ case IntParam(value) => value.toString
+ case DoubleParam(value) => value.toString
+ case StringParam(str) => "\"" + str + "\""
+ case RawParam(str) => "'" + str + "'"
+ }
+ s"parameter $name = $str"
+ }
+
// Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already.
private val defnMap = collection.mutable.HashMap[(String, String), Component]()
@@ -61,12 +72,13 @@ private class Emitter(circuit: Circuit) {
body ++= newline + emitPort(p)
body ++= newline
- m.id match {
- case _: BlackBox =>
- // TODO: BlackBoxes should be empty, but funkiness in Module() means
- // it's not for now. Eventually, this should assert out.
- case _: Module => for (cmd <- m.commands) {
- body ++= newline + emit(cmd, m)
+ m match {
+ case bb: DefBlackBox =>
+ // Firrtl extmodule can overrule name
+ body ++= newline + s"defname = ${bb.id.desiredName}"
+ body ++= newline + (bb.params map { case (n, p) => emitParam(n, p) } mkString newline)
+ case mod: DefModule => for (cmd <- mod.commands) {
+ body ++= newline + emit(cmd, mod)
}
}
body ++= newline
diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala
index e0364868..3cdda971 100644
--- a/src/main/scala/chisel3/package.scala
+++ b/src/main/scala/chisel3/package.scala
@@ -179,4 +179,28 @@ package object chisel3 { // scalastyle:ignore package.object.name
}
def getModulePorts(m: Module): Seq[Port] = m.getPorts
def getFirrtlDirection(d: Data): Direction = chisel3.core.Data.getFirrtlDirection(d)
+
+ /** Package for experimental features, which may have their API changed, be removed, etc.
+ *
+ * Because its contents won't necessarily have the same level of stability and support as
+ * non-experimental, you must explicitly import this package to use its contents.
+ */
+ object experimental {
+ type Param = chisel3.core.Param
+ type IntParam = chisel3.core.IntParam
+ val IntParam = chisel3.core.IntParam
+ type DoubleParam = chisel3.core.DoubleParam
+ val DoubleParam = chisel3.core.DoubleParam
+ type StringParam = chisel3.core.StringParam
+ val StringParam = chisel3.core.StringParam
+ type RawParam = chisel3.core.RawParam
+ val RawParam = chisel3.core.RawParam
+
+ // Implicit conversions for BlackBox Parameters
+ implicit def fromIntToIntParam(x: Int): IntParam = IntParam(BigInt(x))
+ implicit def fromLongToIntParam(x: Long): IntParam = IntParam(BigInt(x))
+ implicit def fromBigIntToIntParam(x: BigInt): IntParam = IntParam(x)
+ implicit def fromDoubleToDoubleParam(x: Double): DoubleParam = DoubleParam(x)
+ implicit def fromStringToStringParam(x: String): StringParam = StringParam(x)
+ }
}
diff --git a/src/test/resources/BlackBoxTest.v b/src/test/resources/BlackBoxTest.v
index 910b09ff..edf321a8 100644
--- a/src/test/resources/BlackBoxTest.v
+++ b/src/test/resources/BlackBoxTest.v
@@ -32,3 +32,28 @@ module BlackBoxConstant #(
);
assign out = VALUE;
endmodule
+
+module BlackBoxStringParam #(
+ parameter string STRING = "zero"
+) (
+ output [31:0] out
+);
+ assign out = (STRING == "one" )? 1 :
+ (STRING == "two" )? 2 : 0;
+endmodule
+
+module BlackBoxRealParam #(
+ parameter real REAL = 0.0
+) (
+ output [63:0] out
+);
+ assign out = $realtobits(REAL);
+endmodule
+
+module BlackBoxTypeParam #(
+ parameter type T = bit
+) (
+ output T out
+);
+ assign out = 32'hdeadbeef;
+endmodule
diff --git a/src/test/scala/chiselTests/BlackBox.scala b/src/test/scala/chiselTests/BlackBox.scala
index 344754e1..d8821134 100644
--- a/src/test/scala/chiselTests/BlackBox.scala
+++ b/src/test/scala/chiselTests/BlackBox.scala
@@ -6,6 +6,7 @@ import java.io.File
import org.scalatest._
import chisel3._
+import chisel3.experimental._
import chisel3.testers.BasicTester
import chisel3.util._
//import chisel3.core.ExplicitCompileOptions.Strict
@@ -84,27 +85,55 @@ class BlackBoxWithClockTester extends BasicTester {
when(end) { stop() }
}
-/*
-// Must determine how to handle parameterized Verilog
-class BlackBoxConstant(value: Int) extends BlackBox {
- val io = IO(new Bundle() {
- val out = Output(UInt(width=log2Up(value)))
+class BlackBoxConstant(value: Int) extends BlackBox(
+ Map("VALUE" -> value, "WIDTH" -> log2Up(value + 1))) {
+ require(value >= 0, "value must be a UInt!")
+ val io = IO(new Bundle {
+ val out = UInt(width = log2Up(value + 1)).asOutput
+ })
+}
+
+class BlackBoxStringParam(str: String) extends BlackBox(Map("STRING" -> str)) {
+ val io = IO(new Bundle {
+ val out = UInt(width = 32)
+ })
+}
+
+class BlackBoxRealParam(dbl: Double) extends BlackBox(Map("REAL" -> dbl)) {
+ val io = IO(new Bundle {
+ val out = UInt(width = 64)
+ })
+}
+
+class BlackBoxTypeParam(w: Int, raw: String) extends BlackBox(Map("T" -> RawParam(raw))) {
+ val io = IO(new Bundle {
+ val out = UInt(width = w)
})
- override val name = s"#(WIDTH=${log2Up(value)},VALUE=$value) "
}
class BlackBoxWithParamsTester extends BasicTester {
val blackBoxOne = Module(new BlackBoxConstant(1))
- val blackBoxFour = Module(new BlackBoxConstant(4))
+ val blackBoxFour = Module(new BlackBoxConstant(4))
+ val blackBoxStringParamOne = Module(new BlackBoxStringParam("one"))
+ val blackBoxStringParamTwo = Module(new BlackBoxStringParam("two"))
+ val blackBoxRealParamOne = Module(new BlackBoxRealParam(1.0))
+ val blackBoxRealParamNeg = Module(new BlackBoxRealParam(-1.0))
+ val blackBoxTypeParamBit = Module(new BlackBoxTypeParam(1, "bit"))
+ val blackBoxTypeParamWord = Module(new BlackBoxTypeParam(32, "bit [31:0]"))
val (cycles, end) = Counter(Bool(true), 4)
assert(blackBoxOne.io.out === UInt(1))
assert(blackBoxFour.io.out === UInt(4))
+ assert(blackBoxStringParamOne.io.out === UInt(1))
+ assert(blackBoxStringParamTwo.io.out === UInt(2))
+ assert(blackBoxRealParamOne.io.out === UInt(0x3ff0000000000000L))
+ assert(blackBoxRealParamNeg.io.out === UInt(BigInt("bff0000000000000", 16)))
+ assert(blackBoxTypeParamBit.io.out === UInt(1))
+ assert(blackBoxTypeParamWord.io.out === UInt("hdeadbeef", 32))
when(end) { stop() }
}
-*/
class BlackBoxSpec extends ChiselFlatSpec {
"A BlackBoxed inverter" should "work" in {
@@ -119,4 +148,8 @@ class BlackBoxSpec extends ChiselFlatSpec {
assertTesterPasses({ new BlackBoxWithClockTester },
Seq("/BlackBoxTest.v"))
}
+ "BlackBoxes with parameters" should "work" in {
+ assertTesterPasses({ new BlackBoxWithParamsTester },
+ Seq("/BlackBoxTest.v"))
+ }
}