diff options
Diffstat (limited to 'chiselFrontend/src/main/scala/Chisel/internal')
3 files changed, 71 insertions, 122 deletions
diff --git a/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala new file mode 100644 index 00000000..66bfc7a4 --- /dev/null +++ b/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala @@ -0,0 +1,51 @@ +// See LICENSE for license details. + +// This file contains macros for adding source locators at the point of invocation. +// +// This is not part of coreMacros to disallow this macro from being implicitly invoked in Chisel +// frontend (and generating source locators in Chisel core), which is almost certainly a bug. +// +// Note: While these functions and definitions are not private (macros can't be +// private), these are NOT meant to be part of the public API (yet) and no +// forward compatibility guarantees are made. +// A future revision may stabilize the source locator API to allow library +// writers to append source locator information at the point of a library +// function invocation. + +package Chisel.internal.sourceinfo + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +/** Abstract base class for generalized source information. + */ +sealed trait SourceInfo + +sealed trait NoSourceInfo extends SourceInfo + +/** For when source info can't be generated because of a technical limitation, like for Reg because + * Scala macros don't support named or default arguments. + */ +case object UnlocatableSourceInfo extends NoSourceInfo + +/** For when source info isn't generated because the function is deprecated and we're lazy. + */ +case object DeprecatedSourceInfo extends NoSourceInfo + +/** For FIRRTL lines from a Scala source line. + */ +case class SourceLine(filename: String, line: Int, col: Int) extends SourceInfo + +/** Provides a macro that returns the source information at the invocation point. + */ +object SourceInfoMacro { + def generate_source_info(c: Context): c.Tree = { + import c.universe._ + val p = c.enclosingPosition + q"_root_.Chisel.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})" + } +} + +object SourceInfo { + implicit def materialize: SourceInfo = macro SourceInfoMacro.generate_source_info +} diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala deleted file mode 100644 index 34547503..00000000 --- a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala +++ /dev/null @@ -1,105 +0,0 @@ -// See LICENSE for license details. - -package Chisel.internal.firrtl -import Chisel._ - -private[Chisel] object Emitter { - def emit(circuit: Circuit): String = new Emitter(circuit).toString -} - -private class Emitter(circuit: Circuit) { - override def toString: String = res.toString - - private def emitPort(e: Port): String = - s"${e.dir} ${e.id.getRef.name} : ${e.id.toType}" - private def emit(e: Command, ctx: Component): String = e match { - case e: DefPrim[_] => s"node ${e.name} = ${e.op.name}(${e.args.map(_.fullName(ctx)).mkString(", ")})" - case e: DefWire => s"wire ${e.name} : ${e.id.toType}" - case e: DefReg => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)}" - case e: DefRegInit => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))" - case e: DefMemory => s"cmem ${e.name} : ${e.t.toType}[${e.size}]" - case e: DefSeqMemory => s"smem ${e.name} : ${e.t.toType}[${e.size}]" - case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}" - case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}" - case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}" - case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})" - case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})""" - case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid" - case e: DefInstance => { - val modName = moduleMap.get(e.id.name).get - s"inst ${e.name} of $modName" - } - - case w: WhenBegin => - indent() - s"when ${w.pred.fullName(ctx)} :" - case _: WhenEnd => - unindent() - "skip" - } - - // Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already. - private val defnMap = collection.mutable.HashMap[String, String]() - // Map of Component name to FIRRTL id. - private val moduleMap = collection.mutable.HashMap[String, String]() - - /** Generates the FIRRTL module definition with a specified name. - */ - private def moduleDefn(m: Component, name: String): String = { - val body = new StringBuilder - m.id match { - case _: BlackBox => body ++= newline + s"extmodule $name : " - case _: Module => body ++= newline + s"module $name : " - } - withIndent { - for (p <- m.ports) - 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) - } - } - body ++= newline - } - body.toString() - } - - /** Returns the FIRRTL declaration and body of a module, or nothing if it's a - * duplicate of something already emitted (on the basis of simple string - * matching). - */ - private def emit(m: Component): String = { - // Generate the body. - val moduleName = m.id.getClass.getName.split('.').last - val defn = moduleDefn(m, moduleName) - - defnMap get defn match { - case Some(deduplicatedName) => - moduleMap(m.name) = deduplicatedName - "" - case None => - require(!(moduleMap contains m.name), - "emitting module with same name but different contents") - - moduleMap(m.name) = m.name - defnMap(defn) = m.name - - moduleDefn(m, m.name) - } - } - - private var indentLevel = 0 - private def newline = "\n" + (" " * indentLevel) - private def indent(): Unit = indentLevel += 1 - private def unindent() { require(indentLevel > 0); indentLevel -= 1 } - private def withIndent(f: => Unit) { indent(); f; unindent() } - - private val res = new StringBuilder(s"circuit ${circuit.name} : ") - withIndent { circuit.components.foreach(c => res ++= emit(c)) } - res ++= newline -} diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala index 91dcf5d2..62784cee 100644 --- a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala @@ -3,6 +3,7 @@ package Chisel.internal.firrtl import Chisel._ import Chisel.internal._ +import Chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} case class PrimOp(val name: String) { override def toString: String = name @@ -142,29 +143,31 @@ object MemPortDirection { object INFER extends MemPortDirection("infer") } -abstract class Command +abstract class Command { + def sourceInfo: SourceInfo +} abstract class Definition extends Command { def id: HasId def name: String = id.getRef.name } -case class DefPrim[T <: Data](id: T, op: PrimOp, args: Arg*) extends Definition -case class DefInvalid(arg: Arg) extends Command -case class DefWire(id: Data) extends Definition -case class DefReg(id: Data, clock: Arg) extends Definition -case class DefRegInit(id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition -case class DefMemory(id: HasId, t: Data, size: Int) extends Definition -case class DefSeqMemory(id: HasId, t: Data, size: Int) extends Definition -case class DefMemPort[T <: Data](id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition -case class DefInstance(id: Module, ports: Seq[Port]) extends Definition -case class WhenBegin(pred: Arg) extends Command -case class WhenEnd() extends Command -case class Connect(loc: Node, exp: Arg) extends Command -case class BulkConnect(loc1: Node, loc2: Node) extends Command -case class ConnectInit(loc: Node, exp: Arg) extends Command -case class Stop(clk: Arg, ret: Int) extends Command +case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition +case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command +case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition +case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition +case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition +case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition +case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition +case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition +case class DefInstance(sourceInfo: SourceInfo, id: Module, ports: Seq[Port]) extends Definition +case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command +case class WhenEnd(sourceInfo: SourceInfo) extends Command +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, clk: 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(clk: Arg, formatIn: String, ids: Seq[Arg]) extends Command { +case class Printf(sourceInfo: SourceInfo, clk: Arg, formatIn: String, ids: Seq[Arg]) extends Command { require(formatIn.forall(c => c.toInt > 0 && c.toInt < 128), "format strings must comprise non-null ASCII values") def format: String = { def escaped(x: Char) = { |
