diff options
| author | jackkoenig | 2016-09-22 19:10:40 -0700 |
|---|---|---|
| committer | Jack Koenig | 2016-10-26 15:15:37 -0700 |
| commit | 4b8a0d2af52ceeb3ff5d05082af53bac76744361 (patch) | |
| tree | 3c416fe2532c504cff18efc8b6d0dccab207802a /src | |
| parent | e25c6f7a5e4e1bfbfcb8345288be478caa469525 (diff) | |
Add Support for Parameterized ExtModules and Name Override
Adds support for Integer, Double/Real, and String parameters in external
modules. Also add name field to extmodules so that emitted name can be
different from Firrtl name. This is important because parameterized extmodules
will frequently have differing IO even though they need to be emitted as
instantiating the same Verilog module.
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/antlr4/FIRRTL.g4 | 16 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Emitter.scala | 20 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Visitor.scala | 16 | ||||
| -rw-r--r-- | src/main/scala/firrtl/ir/IR.scala | 29 | ||||
| -rw-r--r-- | src/main/scala/firrtl/passes/ConvertFixedToSInt.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala | 2 | ||||
| -rw-r--r-- | src/test/resources/blackboxes/ParameterizedExtModule.v | 15 | ||||
| -rw-r--r-- | src/test/resources/blackboxes/ParameterizedExtModuleTester.fir | 40 | ||||
| -rw-r--r-- | src/test/resources/blackboxes/RenamedExtModuleTester.fir | 22 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/ExtModuleSpec.scala | 4 |
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")) |
