aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/antlr4/FIRRTL.g416
-rw-r--r--src/main/scala/firrtl/Emitter.scala20
-rw-r--r--src/main/scala/firrtl/Visitor.scala16
-rw-r--r--src/main/scala/firrtl/ir/IR.scala29
-rw-r--r--src/main/scala/firrtl/passes/ConvertFixedToSInt.scala2
-rw-r--r--src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala2
-rw-r--r--src/test/resources/blackboxes/ParameterizedExtModule.v15
-rw-r--r--src/test/resources/blackboxes/ParameterizedExtModuleTester.fir40
-rw-r--r--src/test/resources/blackboxes/RenamedExtModuleTester.fir22
-rw-r--r--src/test/scala/firrtlTests/ExtModuleSpec.scala4
10 files changed, 157 insertions, 9 deletions
diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4
index 4ceed9f0..f4d9d3f8 100644
--- a/src/main/antlr4/FIRRTL.g4
+++ b/src/main/antlr4/FIRRTL.g4
@@ -63,7 +63,7 @@ circuit
module
: 'module' id ':' info? INDENT port* moduleBlock DEDENT
- | 'extmodule' id ':' info? INDENT port* DEDENT
+ | 'extmodule' id ':' info? INDENT port* defname? parameter* DEDENT
;
port
@@ -89,6 +89,16 @@ field
: 'flip'? id ':' type
;
+defname
+ : 'defname' '=' id NEWLINE
+ ;
+
+parameter
+ : 'parameter' id '=' IntLit NEWLINE
+ | 'parameter' id '=' StringLit NEWLINE
+ | 'parameter' id '=' DoubleLit NEWLINE
+ ;
+
moduleBlock
: simple_stmt*
;
@@ -291,6 +301,10 @@ IntLit
| '"' 'h' ( HexDigit )+ '"'
;
+DoubleLit
+ : ( '+' | '-' )? Digit+ '.' Digit+ ( 'E' Digit+ )?
+ ;
+
fragment
Nondigit
: [a-zA-Z_]
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index 405019b7..e3a146e2 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -82,6 +82,14 @@ class VerilogEmitter extends Emitter {
}
case _ => error("Shouldn't be here")
}
+ /** Turn Params into Verilog Strings */
+ def stringify(param: Param): String = param match {
+ case IntParam(name, value) => s".$name($value)"
+ case DoubleParam(name, value) => s".$name($value)"
+ case StringParam(name, value) =>
+ val strx = "\"" + VerilogStringLitHandler.escape(value) + "\""
+ s".${name}($strx)"
+ }
def emit(x: Any)(implicit w: Writer) { emit(x, 0) }
def emit(x: Any, top: Int)(implicit w: Writer) {
def cast(e: Expression): Any = e.tpe match {
@@ -237,7 +245,7 @@ class VerilogEmitter extends Emitter {
}
}
- def emit_verilog(m: Module)(implicit w: Writer): DefModule = {
+ def emit_verilog(m: Module, moduleMap: Map[String, DefModule])(implicit w: Writer): DefModule = {
val netlist = mutable.LinkedHashMap[WrappedExpression, Expression]()
val addrRegs = mutable.HashSet[WrappedExpression]()
val namespace = Namespace(m)
@@ -448,8 +456,13 @@ class VerilogEmitter extends Emitter {
simulate(sx.clk, sx.en, printf(sx.string, sx.args), Some("PRINTF_COND"))
sx
case sx: WDefInstanceConnector =>
+ val (module, params) = moduleMap(sx.module) match {
+ case ExtModule(_, _, _, extname, params) => (extname, params)
+ case Module(_, name, _, _) => (name, Seq.empty)
+ }
val es = create_exps(WRef(sx.name, sx.tpe, InstanceKind, MALE))
- instdeclares += Seq(sx.module, " ", sx.name, " (")
+ val ps = if (params.nonEmpty) params map stringify mkString ("#(", ", ", ") ") else ""
+ instdeclares += Seq(module, " ", ps, sx.name ," (")
(es zip sx.exprs).zipWithIndex foreach {case ((l, r), i) =>
val s = Seq(tab, ".", remove_root(l), "(", r, ")")
if (i != es.size - 1) instdeclares += Seq(s, ",")
@@ -581,8 +594,9 @@ class VerilogEmitter extends Emitter {
def run(c: Circuit, w: Writer) = {
emit_preamble(w)
+ val moduleMap = (c.modules map (m => m.name -> m)).toMap
c.modules foreach {
- case (m: Module) => emit_verilog(m)(w)
+ case (m: Module) => emit_verilog(m, moduleMap)(w)
case (m: ExtModule) =>
}
}
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
index d45283c6..03be0c4e 100644
--- a/src/main/scala/firrtl/Visitor.scala
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -105,7 +105,11 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
if (ctx.moduleBlock() != null)
visitBlock(ctx.moduleBlock())
else EmptyStmt)
- case "extmodule" => ExtModule(info, ctx.id.getText, ctx.port.map(visitPort))
+ case "extmodule" =>
+ val defname = if (ctx.defname != null) ctx.defname.id.getText else ctx.id.getText
+ val ports = ctx.port map visitPort
+ val params = ctx.parameter map visitParameter
+ ExtModule(info, ctx.id.getText, ports, defname, params)
}
}
@@ -113,6 +117,16 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
Port(visitInfo(Option(ctx.info), ctx), ctx.id.getText, visitDir(ctx.dir), visitType(ctx.`type`))
}
+ private def visitParameter[FirrtlNode](ctx: FIRRTLParser.ParameterContext): Param = {
+ val name = ctx.id.getText
+ (ctx.IntLit, ctx.StringLit, ctx.DoubleLit) match {
+ case (int, null, null) => IntParam(name, string2BigInt(int.getText))
+ case (null, str, null) => StringParam(name, visitStringLit(str))
+ case (null, null, dbl) => DoubleParam(name, dbl.getText.toDouble)
+ case _ => throw new Exception(s"Internal error: Visiting impossible parameter ${ctx.getText}")
+ }
+ }
+
private def visitDir[FirrtlNode](ctx: FIRRTLParser.DirContext): Direction =
ctx.getText match {
case "input" => Input
diff --git a/src/main/scala/firrtl/ir/IR.scala b/src/main/scala/firrtl/ir/IR.scala
index f5b80ac6..b9b31427 100644
--- a/src/main/scala/firrtl/ir/IR.scala
+++ b/src/main/scala/firrtl/ir/IR.scala
@@ -440,6 +440,24 @@ case class Port(
def serialize: String = s"${direction.serialize} $name : ${tpe.serialize}" + info.serialize
}
+/** Parameters for external modules */
+sealed abstract class Param extends FirrtlNode {
+ def name: String
+ def serialize: String = s"parameter $name = "
+}
+/** Integer (of any width) Parameter */
+case class IntParam(name: String, value: BigInt) extends Param {
+ override def serialize: String = super.serialize + value
+}
+/** IEEE Double Precision Parameter (for Verilog real) */
+case class DoubleParam(name: String, value: Double) extends Param {
+ override def serialize: String = super.serialize + value
+}
+/** String Parameter */
+case class StringParam(name: String, value: StringLit) extends Param {
+ override def serialize: String = super.serialize + value.serialize
+}
+
/** Base class for modules */
abstract class DefModule extends FirrtlNode with IsDeclaration {
val info : Info
@@ -464,9 +482,16 @@ case class Module(info: Info, name: String, ports: Seq[Port], body: Statement) e
/** External Module
*
* Generally used for Verilog black boxes
+ * @param defname Defined name of the external module (ie. the name Firrtl will emit)
*/
-case class ExtModule(info: Info, name: String, ports: Seq[Port]) extends DefModule {
- def serialize: String = serializeHeader("extmodule")
+case class ExtModule(
+ info: Info,
+ name: String,
+ ports: Seq[Port],
+ defname: String,
+ params: Seq[Param]) extends DefModule {
+ def serialize: String = serializeHeader("extmodule") +
+ indent(s"\ndefname = $defname\n" + params.map(_.serialize).mkString("\n"))
def mapStmt(f: Statement => Statement): DefModule = this
def mapPort(f: Port => Port): DefModule = this.copy(ports = ports map f)
def mapString(f: String => String): DefModule = this.copy(name = f(name))
diff --git a/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala b/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala
index 8cf0b890..e334b94f 100644
--- a/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala
+++ b/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala
@@ -108,7 +108,7 @@ object ConvertFixedToSInt extends Pass {
val newPorts = m.ports.map(p => Port(p.info,p.name,p.direction,toSIntType(p.tpe)))
m match {
case Module(info, name, ports, body) => Module(info,name,newPorts,body)
- case ExtModule(info, name, ports) => ExtModule(info,name,newPorts)
+ case ext: ExtModule => ext.copy(ports = newPorts)
}
}
newModules.foreach(m => moduleTypes(m.name) = module_type(m))
diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala
index 5fc99b9c..91e4efea 100644
--- a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala
+++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala
@@ -96,7 +96,7 @@ class ReplaceMemMacros(writer: ConfWriter) extends Pass {
(m.writers flatMap (w => adaptWriter(portRef(w), createSubField(bbRef, w), hasMask, fillMask))) ++
(m.readwriters flatMap (rw => adaptReadWriter(portRef(rw), createSubField(bbRef, rw), hasMask, fillMask)))
val wrapper = Module(NoInfo, wrapperName, wrapperIoPorts, Block(stmts))
- val bb = ExtModule(NoInfo, m.name, bbIoPorts)
+ val bb = ExtModule(NoInfo, m.name, bbIoPorts, m.name, Seq.empty)
// TODO: Annotate? -- use actual annotation map
// add to conf file
diff --git a/src/test/resources/blackboxes/ParameterizedExtModule.v b/src/test/resources/blackboxes/ParameterizedExtModule.v
new file mode 100644
index 00000000..ee6e3ec3
--- /dev/null
+++ b/src/test/resources/blackboxes/ParameterizedExtModule.v
@@ -0,0 +1,15 @@
+
+module ParameterizedExtModule(
+ input [15:0] foo,
+ output [15:0] bar
+);
+ parameter VALUE = 0;
+ parameter STRING = "one";
+ parameter REAL = 1.0;
+ wire [15:0] fizz;
+ wire [15:0] buzz;
+ assign bar = foo + VALUE + fizz + buzz;
+ assign fizz = (STRING == "two")? 2 : (STRING == "one")? 1 : 0;
+ assign buzz = (REAL > 2.5E50)? 2 : (REAL < 0.0)? 1 : 0;
+endmodule
+
diff --git a/src/test/resources/blackboxes/ParameterizedExtModuleTester.fir b/src/test/resources/blackboxes/ParameterizedExtModuleTester.fir
new file mode 100644
index 00000000..29769e84
--- /dev/null
+++ b/src/test/resources/blackboxes/ParameterizedExtModuleTester.fir
@@ -0,0 +1,40 @@
+circuit ParameterizedExtModuleTester :
+ extmodule ParameterizedExtModule_1 :
+ input foo : UInt<16>
+ output bar : UInt<16>
+
+ defname = ParameterizedExtModule
+ parameter VALUE = 1
+ parameter STRING = "one"
+ parameter REAL = -1.7
+
+ extmodule ParameterizedExtModule_2 :
+ input foo : UInt<16>
+ output bar : UInt<16>
+
+ defname = ParameterizedExtModule
+ parameter VALUE = 2
+ parameter STRING = "two"
+ parameter REAL = 2.6E50
+
+ module ParameterizedExtModuleTester :
+ input clk : Clock
+ input reset : UInt<1>
+
+ inst dut1 of ParameterizedExtModule_1
+ inst dut2 of ParameterizedExtModule_2
+
+ dut1.foo <= UInt(1000)
+ dut2.foo <= UInt(1000)
+
+ when not(reset) :
+ when neq(dut1.bar, UInt(1003)) :
+ printf(clk, not(reset), "Assertion failed\nTest Failed!\n")
+ stop(clk, not(reset), 1)
+ else :
+ when neq(dut2.bar, UInt(1006)) :
+ printf(clk, not(reset), "Assertion failed\nTest Failed!\n")
+ stop(clk, not(reset), 1)
+ else :
+ stop(clk, not(reset), 0)
+
diff --git a/src/test/resources/blackboxes/RenamedExtModuleTester.fir b/src/test/resources/blackboxes/RenamedExtModuleTester.fir
new file mode 100644
index 00000000..48b0886c
--- /dev/null
+++ b/src/test/resources/blackboxes/RenamedExtModuleTester.fir
@@ -0,0 +1,22 @@
+circuit RenamedExtModuleTester :
+ extmodule ThisIsJustTheFirrtlName :
+ input foo : UInt<16>
+ output bar : UInt<16>
+
+ defname = SimpleExtModule
+
+ module RenamedExtModuleTester :
+ input clk : Clock
+ input reset : UInt<1>
+
+ inst dut of ThisIsJustTheFirrtlName
+
+ dut.foo <= UInt(1234)
+
+ when not(reset) :
+ when neq(dut.bar, UInt(1234)) :
+ printf(clk, not(reset), "Assertion failed\nTest Failed!\n")
+ stop(clk, not(reset), 1)
+ else :
+ stop(clk, not(reset), 0)
+
diff --git a/src/test/scala/firrtlTests/ExtModuleSpec.scala b/src/test/scala/firrtlTests/ExtModuleSpec.scala
index ba36e5f2..b7866de1 100644
--- a/src/test/scala/firrtlTests/ExtModuleSpec.scala
+++ b/src/test/scala/firrtlTests/ExtModuleSpec.scala
@@ -31,4 +31,8 @@ class SimpleExtModuleExecutionTest extends ExecutionTest("SimpleExtModuleTester"
Seq("SimpleExtModule"))
class MultiExtModuleExecutionTest extends ExecutionTest("MultiExtModuleTester", "/blackboxes",
Seq("SimpleExtModule", "AdderExtModule"))
+class RenamedExtModuleExecutionTest extends ExecutionTest("RenamedExtModuleTester", "/blackboxes",
+ Seq("SimpleExtModule"))
+class ParameterizedExtModuleExecutionTest extends ExecutionTest(
+ "ParameterizedExtModuleTester", "/blackboxes", Seq("ParameterizedExtModule"))