diff options
Diffstat (limited to 'src/main/scala/Chisel/Core.scala')
| -rw-r--r-- | src/main/scala/Chisel/Core.scala | 280 |
1 files changed, 115 insertions, 165 deletions
diff --git a/src/main/scala/Chisel/Core.scala b/src/main/scala/Chisel/Core.scala index 2514c7d9..7fdd35bf 100644 --- a/src/main/scala/Chisel/Core.scala +++ b/src/main/scala/Chisel/Core.scala @@ -6,7 +6,7 @@ import java.lang.reflect.Modifier._ import java.lang.Double.longBitsToDouble import java.lang.Float.intBitsToFloat -class IdGen { +private class IdGen { private var counter = -1L def next: Long = { counter += 1 @@ -38,73 +38,34 @@ private class ChiselRefMap { } private object DynamicContext { - val currentParentVar = new DynamicVariable[Option[Module]](None) + val currentModuleVar = new DynamicVariable[Option[Module]](None) val currentParamsVar = new DynamicVariable[Parameters](Parameters.empty) - val currentCommandsVar = new DynamicVariable[ArrayBuffer[Command]](new ArrayBuffer[Command]()) - def getParentModule = currentParentVar.value - def parentModuleScope[T](m: Option[Module])(body: => T): T = { - currentParentVar.withValue(m)(body) + def getCurrentModule = currentModuleVar.value + def moduleScope[T](body: => T): T = { + currentModuleVar.withValue(getCurrentModule)(body) } - def forceParentModule[T](m: Module) { - currentParentVar.value = Some(m) + def forceCurrentModule[T](m: Module) { // Used in Module constructor + currentModuleVar.value = Some(m) + } + def pushCommand(c: Command) { + currentModuleVar.value.foreach(_._commands += c) } def getParams: Parameters = currentParamsVar.value def paramsScope[T](p: Parameters)(body: => T): T = { currentParamsVar.withValue(p)(body) } - - def getCommands: Command = { - val cmds = currentCommandsVar.value - if (cmds.length == 0) EmptyCommand() - else if (cmds.length == 1) cmds(0) - else Begin(cmds.toList) - } - def pushCommand(c: Command) { - currentCommandsVar.value += c - } - def commandsScope[T](body: => T): (T, Command) = { - currentCommandsVar.withValue(new ArrayBuffer[Command]()){ - val r = body - val c = getCommands - (r, c) - } - } } private object Builder { - val globalNamespace = new FIRRTLNamespace - val globalRefMap = new ChiselRefMap val idGen = new IdGen - - val components = new ArrayBuffer[Component]() - val commandz = new Stack[ArrayBuffer[Command]]() - def commands = commandz.top - def pushCommand(cmd: Command) = commands += cmd - def commandify(cmds: ArrayBuffer[Command]): Command = { - if (cmds.length == 0) - EmptyCommand() - else if (cmds.length == 1) - cmds(0) - else - Begin(cmds.toList) - } - def pushCommands = - commandz.push(new ArrayBuffer[Command]()) - def popCommands: Command = { - val newCommands = commands - commandz.pop() - commandify(newCommands) - } - def collectCommands[T <: Module](f: => T): (Command, T) = { - pushCommands - val mod = f - (popCommands, mod) - } + val globalNamespace = new FIRRTLNamespace + val globalRefMap = new ChiselRefMap // TODO: mutable + val components = new ArrayBuffer[Component]() //TODO: mutable def build[T <: Module](f: => T): Circuit = { - val (cmd, mod) = collectCommands(f) + val mod = f Builder.globalRefMap.setRefForId(mod, mod.name) Circuit(components, components.last.name) } @@ -116,9 +77,7 @@ object build { } } -import Builder.pushCommand -import Builder.pushCommands -import Builder.popCommands +import DynamicContext.pushCommand /// CHISEL IR @@ -284,17 +243,16 @@ case class DefRegister(id: Id, kind: Kind, clock: Clock, reset: Bool) extends De case class DefMemory(id: Id, kind: Kind, size: Int, clock: Clock) extends Definition case class DefSeqMemory(id: Id, kind: Kind, size: Int) extends Definition case class DefAccessor(id: Id, source: Alias, direction: Direction, index: Arg) extends Definition -case class DefInstance(id: Module, module: String, ports: Seq[Port]) extends Definition -case class Conditionally(val prep: Command, val pred: Arg, val conseq: Command, var alt: Command) extends Command; -case class Begin(val body: List[Command]) extends Command(); -case class Connect(val loc: Alias, val exp: Arg) extends Command; -case class BulkConnect(val loc1: Alias, val loc2: Alias) extends Command; -case class ConnectInit(val loc: Alias, val exp: Arg) extends Command; -case class ConnectInitIndex(val loc: Alias, val index: Int, val exp: Arg) extends Command; -case class EmptyCommand() extends Command; - -case class Component(val name: String, val ports: Seq[Port], val body: Command); -case class Circuit(val components: Seq[Component], val main: String); +case class DefInstance(id: Module, ports: Seq[Port]) extends Definition +case class WhenBegin(pred: Arg) extends Command +case class WhenElse() extends Command +case class WhenEnd() extends Command +case class Connect(loc: Alias, exp: Arg) extends Command +case class BulkConnect(loc1: Alias, loc2: Alias) extends Command +case class ConnectInit(loc: Alias, exp: Arg) extends Command + +case class Component(name: String, ports: Seq[Port], commands: Seq[Command]) +case class Circuit(components: Seq[Component], main: String) object Commands { val NoLits = Seq[BigInt]() @@ -324,11 +282,11 @@ object debug { } abstract class Data(dirArg: Direction) extends Id { - private[Chisel] val _mod: Module = DynamicContext.getParentModule.getOrElse( + private[Chisel] val _mod: Module = DynamicContext.getCurrentModule.getOrElse( throwException("Data subclasses can only be instantiated inside Modules!")) //TODO: is this true? - _mod.addNode(Some(this)) + _mod.addNode(this) def params = DynamicContext.getParams def toType: Kind @@ -336,16 +294,15 @@ abstract class Data(dirArg: Direction) extends Id { // Sucks this is mutable state, but cloneType doesn't take a Direction arg private var isFlipVar = dirArg == INPUT - private[Chisel] var dirVar = dirArg + private var dirVar = dirArg private[Chisel] def isFlip = isFlipVar private def cloneWithDirection(newDir: Direction => Direction, newFlip: Boolean => Boolean): this.type = { val res = this.cloneType res.isFlipVar = newFlip(res.isFlipVar) - for ((me, it) <- this.flatten zip res.flatten) { - it.dirVar = newDir(me.dirVar) - } + for ((me, it) <- this.flatten zip res.flatten) + (it: Data).dirVar = newDir((me: Data).dirVar) res } def asInput: this.type = cloneWithDirection(_ => INPUT, _ => true) @@ -1033,8 +990,8 @@ class Bundle extends Aggregate(NO_DIR) { case npe: java.lang.reflect.InvocationTargetException if npe.getCause.isInstanceOf[java.lang.NullPointerException] => ChiselError.error(s"Parameterized Bundle ${this.getClass} needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable") this - case e: java.lang.Exception => - ChiselError.error(s"Parameterized Bundle ${this.getClass} needs cloneType method") + case npe: java.lang.reflect.InvocationTargetException => + ChiselError.error(s"Parameterized Bundle ${this.getClass} needs cloneType method") this } } @@ -1043,10 +1000,10 @@ class Bundle extends Aggregate(NO_DIR) { object Module { def apply[T <: Module](bc: => T)(implicit currParams: Parameters = DynamicContext.getParams): T = { DynamicContext.paramsScope(currParams.push) { - val m = DynamicContext.parentModuleScope(None) { bc.setRefs() } + val m = DynamicContext.moduleScope{ bc.setRefs() } val ports = m.computePorts - Builder.components += Component(m.name, ports, popCommands) - pushCommand(DefInstance(m, m.name, ports)) + Builder.components += Component(m.name, ports, m._commands) + pushCommand(DefInstance(m, ports)) m }.connectImplicitIOs() } @@ -1057,13 +1014,13 @@ object Module { } abstract class Module(_clock: Clock = null, _reset: Bool = null) extends Id { - private val _parent = DynamicContext.getParentModule - private val _nodes = ArrayBuffer[Data]() private implicit val _namespace = new ChildNamespace(Builder.globalNamespace) - val name = Builder.globalNamespace.name(getClass.getName.split('.').last) + private[Chisel] val _commands = ArrayBuffer[Command]() + private[Chisel] val _nodes = ArrayBuffer[Data]() + private[Chisel] val _parent = DynamicContext.getCurrentModule + DynamicContext.forceCurrentModule(this) - DynamicContext.forceParentModule(this) - pushCommands + val name = Builder.globalNamespace.name(getClass.getName.split('.').last) private def params = DynamicContext.getParams params.path = this.getClass :: params.path //TODO: make immutable? @@ -1075,7 +1032,7 @@ abstract class Module(_clock: Clock = null, _reset: Bool = null) extends Id { private[Chisel] def ref = Builder.globalRefMap.getRefForId(this) private[Chisel] def lref = ref - def addNode(d: Option[Data]) { d.map(_nodes += _) } + def addNode(d: Data) { _nodes += d } def debugName: String = _parent match { case Some(p) => s"${p.debugName}.${ref.debugName}" @@ -1140,57 +1097,38 @@ abstract class BlackBox(_clock: Clock = null, _reset: Bool = null) extends Modul } object when { - private[Chisel] def execBlock(block: => Unit): Command = { - pushCommands - block - val cmd = popCommands - cmd - } - def apply(cond: => Bool)(block: => Unit): when = { - new when(cond)( block ) + def apply(cond: => Bool)(block: => Unit): WhenContext = { + new WhenContext(cond)(block) } } -class when(cond: => Bool)(block: => Unit) { - def elsewhen (cond: => Bool)(block: => Unit): when = { - pushCommands - val res = new when(cond) ( block ) - this.cmd.alt = popCommands - res - } +class WhenContext(cond: => Bool)(block: => Unit) { + def elsewhen (cond: => Bool)(block: => Unit): WhenContext = + doOtherwise(when(cond)(block)) - def otherwise (block: => Unit) { - this.cmd.alt = when.execBlock(block) - } + def otherwise(block: => Unit): Unit = + doOtherwise(block) + + pushCommand(WhenBegin(cond.ref)) + block + pushCommand(WhenEnd()) - // Capture any commands we need to set up the conditional test. - pushCommands - val pred = cond.ref - val prep = popCommands - val conseq = when.execBlock(block) - // Assume we have an empty alternate clause. - // elsewhen and otherwise will update it if that isn't the case. - val cmd = Conditionally(prep, pred, conseq, EmptyCommand()) - pushCommand(cmd) + private def doOtherwise[T](block: => T): T = { + pushCommand(WhenElse()) + val res = block + pushCommand(WhenEnd()) + res + } } /// CHISEL IR EMITTER -class Emitter { - private var indenting = 0 - def withIndent(f: => String) = { - indenting += 1 - val res = f - indenting -= 1 - res - } +class Emitter(circuit: Circuit) { + override def toString = res.toString - def newline = "\n" + (" " * indenting) def join(parts: Seq[String], sep: String): StringBuilder = parts.tail.foldLeft(new StringBuilder(parts.head))((s, p) => s ++= sep ++= p) - def join0(parts: Seq[String], sep: String): StringBuilder = - parts.foldLeft(new StringBuilder)((s, p) => s ++= sep ++= p) def emitDir(e: Port, isTop: Boolean): String = if (isTop) (if (e.id.isFlip) "input " else "output ") else (if (e.id.isFlip) "flip " else "") @@ -1198,17 +1136,15 @@ class Emitter { def emit(e: Arg): String = e.fullname def emitPort(e: Port, isTop: Boolean): String = s"${emitDir(e, isTop)}${Builder.globalRefMap.getRefForId(e.id).name} : ${emitType(e.kind)}" - def emitType(e: Kind): String = { - e match { - case e: UnknownType => "?" - case e: UIntType => s"UInt<${e.width}>" - case e: SIntType => s"SInt<${e.width}>" - case e: BundleType => s"{${join(e.ports.map(x => emitPort(x, false)), ", ")}}" - case e: VectorType => s"${emitType(e.kind)}[${e.size}]" - case e: ClockType => s"Clock" - } - } - def emit(e: Command): String = e match { + private def emitType(e: Kind): String = e match { + case e: UnknownType => "?" + case e: UIntType => s"UInt<${e.width}>" + case e: SIntType => s"SInt<${e.width}>" + case e: BundleType => s"{${join(e.ports.map(x => emitPort(x, false)), ", ")}}" + case e: VectorType => s"${emitType(e.kind)}[${e.size}]" + case e: ClockType => s"Clock" + } + private def emit(e: Command): String = e match { case e: DefUInt => s"node ${e.name} = UInt<${e.width}>(${e.value})" case e: DefSInt => s"node ${e.name} = SInt<${e.width}>(${e.value})" case e: DefFlo => s"node ${e.name} = Flo(${e.value})" @@ -1219,46 +1155,60 @@ class Emitter { case e: DefMemory => s"cmem ${e.name} : ${emitType(e.kind)}[${e.size}], ${e.clock.name}"; case e: DefSeqMemory => s"smem ${e.name} : ${emitType(e.kind)}[${e.size}]"; case e: DefAccessor => s"infer accessor ${e.name} = ${emit(e.source)}[${emit(e.index)}]" - case e: DefInstance => { - val mod = e.id - // update all references to the modules ports - Builder.globalRefMap.overrideRefForId(mod.io, e.name) - "inst " + e.name + " of " + e.module + newline + join0(e.ports.flatMap(x => initPort(x, INPUT)), newline) - } - case e: Conditionally => { - val prefix = if (!e.prep.isInstanceOf[EmptyCommand]) { - newline + emit(e.prep) + newline - } else { - "" - } - val suffix = if (!e.alt.isInstanceOf[EmptyCommand]) { - newline + "else : " + withIndent{ newline + emit(e.alt) } - } else { - "" - } - prefix + "when " + emit(e.pred) + " : " + withIndent{ emit(e.conseq) } + suffix - } - case e: Begin => join0(e.body.map(x => emit(x)), newline).toString case e: Connect => s"${emit(e.loc)} := ${emit(e.exp)}" case e: BulkConnect => s"${emit(e.loc1)} <> ${emit(e.loc2)}" case e: ConnectInit => s"onreset ${emit(e.loc)} := ${emit(e.exp)}" - case e: ConnectInitIndex => s"onreset ${emit(e.loc)}[${e.index}] := ${emit(e.exp)}" - case e: EmptyCommand => "skip" - } - def initPort(p: Port, dir: Direction) = { + case e: DefInstance => { + // From now on, all references to the IOs occur from within the parent + Builder.globalRefMap.overrideRefForId(e.id.io, e.name) + + val res = new StringBuilder(s"inst ${e.name} of ${e.id.name}") + res ++= newline + for (p <- e.ports; x <- initPort(p, INPUT)) + res ++= newline + x + res.toString + } + + case w: WhenBegin => + indent() + s"when ${emit(w.pred)} :" + case _: WhenElse => + indent() + "else :" + case _: WhenEnd => + unindent() + "skip" + } + private def initPort(p: Port, dir: Direction) = { for (x <- p.id.flatten; if x.dir == dir) yield s"${Builder.globalRefMap.getRefForId(x).fullname} := ${emit(x.makeLit(0).ref)}" } - def emit(e: Component): String = { - withIndent{ "module " + e.name + " : " + - join0(e.ports.map(x => emitPort(x, true)), newline) + - newline + join0(e.ports.flatMap(x => initPort(x, OUTPUT)), newline) + - newline + emit(e.body) } + + private def emit(m: Component): Unit = { + res ++= newline + s"module ${m.name} : " + withIndent { + for (p <- m.ports) + res ++= newline + emitPort(p, true) + res ++= newline + for (p <- m.ports; x <- initPort(p, OUTPUT)) + res ++= newline + x + res ++= newline + for (cmd <- m.commands) + res ++= newline + emit(cmd) + res ++= newline + } } - def emit(e: Circuit): String = - withIndent{ "circuit " + e.main + " : " + join0(e.components.map(x => emit(x)), newline) } + newline + + 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.main} : ") + withIndent { circuit.components foreach emit } } object emit { - def apply(e: Circuit) = new Emitter().emit(e) + def apply(e: Circuit) = new Emitter(e).toString } |
