diff options
Diffstat (limited to 'chiselFrontend')
18 files changed, 508 insertions, 287 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Attach.scala b/chiselFrontend/src/main/scala/chisel3/core/Attach.scala index 5e767b84..edc0a7c9 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Attach.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Attach.scala @@ -14,7 +14,7 @@ object attach { // scalastyle:ignore object.name AttachException(": Conditional attach is not allowed!") // Actual implementation - private[core] def impl(elts: Seq[Analog], contextModule: Module)(implicit sourceInfo: SourceInfo): Unit = { + private[core] def impl(elts: Seq[Analog], contextModule: UserModule)(implicit sourceInfo: SourceInfo): Unit = { if (Builder.whenDepth != 0) throw ConditionalAttachException // TODO Check that references are valid and can be attached @@ -35,7 +35,7 @@ object attach { // scalastyle:ignore object.name */ def apply(elts: Analog*)(implicit sourceInfo: SourceInfo): Unit = { try { - impl(elts, Builder.forcedModule) + impl(elts, Builder.forcedUserModule) } catch { case AttachException(message) => throwException(elts.mkString("Attaching (", ", ", s") failed @$message")) diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 825dbad7..95ad95ef 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -54,7 +54,7 @@ object BiConnect { * during the recursive decent and then rethrow them with extra information added. * This gives the user a 'path' to where in the connections things went wrong. */ - def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Data, right: Data, context_mod: Module): Unit = + def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Data, right: Data, context_mod: UserModule): Unit = (left, right) match { // Handle element case (root case) case (left_a: Analog, right_a: Analog) => @@ -121,12 +121,12 @@ object BiConnect { // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. - def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Element, right: Element, context_mod: Module): Unit = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Element, right: Element, context_mod: UserModule): Unit = { import Direction.{Input, Output} // Using extensively so import these // If left or right have no location, assume in context module // This can occur if one of them is a literal, unbound will error previously - val left_mod: Module = left.binding.location.getOrElse(context_mod) - val right_mod: Module = right.binding.location.getOrElse(context_mod) + val left_mod: BaseModule = left.binding.location.getOrElse(context_mod) + val right_mod: BaseModule = right.binding.location.getOrElse(context_mod) val left_direction: Option[Direction] = left.binding.direction val right_direction: Option[Direction] = right.binding.direction @@ -250,7 +250,7 @@ object BiConnect { // This function checks if analog element-level attaching is allowed // Then it either issues it or throws the appropriate exception. - def analogAttach(implicit sourceInfo: SourceInfo, left: Analog, right: Analog, contextModule: Module): Unit = { + def analogAttach(implicit sourceInfo: SourceInfo, left: Analog, right: Analog, contextModule: UserModule): Unit = { // Error if left or right is BICONNECTED in the current module already for (elt <- left :: right :: Nil) { elt.biConnectLocs.get(contextModule) match { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala index c7346dce..d872d7c6 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala @@ -41,24 +41,24 @@ case object LitBinder extends Binder[LitBinding] { def apply(in: UnboundBinding) = LitBinding() } -case class MemoryPortBinder(enclosure: Module) extends Binder[MemoryPortBinding] { +case class MemoryPortBinder(enclosure: UserModule) extends Binder[MemoryPortBinding] { def apply(in: UnboundBinding) = MemoryPortBinding(enclosure) } -case class OpBinder(enclosure: Module) extends Binder[OpBinding] { +case class OpBinder(enclosure: UserModule) extends Binder[OpBinding] { def apply(in: UnboundBinding) = OpBinding(enclosure) } // Notice how PortBinder uses the direction of the UnboundNode -case class PortBinder(enclosure: Module) extends Binder[PortBinding] { +case class PortBinder(enclosure: BaseModule) extends Binder[PortBinding] { def apply(in: UnboundBinding) = PortBinding(enclosure, in.direction) } -case class RegBinder(enclosure: Module) extends Binder[RegBinding] { +case class RegBinder(enclosure: UserModule) extends Binder[RegBinding] { def apply(in: UnboundBinding) = RegBinding(enclosure) } -case class WireBinder(enclosure: Module) extends Binder[WireBinding] { +case class WireBinder(enclosure: UserModule) extends Binder[WireBinding] { def apply(in: UnboundBinding) = WireBinding(enclosure) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index a857ae85..87e706b7 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -91,8 +91,6 @@ object Binding { case unbound @ UnboundBinding(_) => { element.binding = binder(unbound) } - // If autoIOWrap is enabled and we're rebinding a PortBinding, just ignore the rebinding. - case portBound @ PortBinding(_, _) if (!(forcedModule.compileOptions.requireIOWrap) && binder.isInstanceOf[PortBinder]) => case binding => throw AlreadyBoundException(binding.toString) } ) @@ -118,68 +116,32 @@ object Binding { // Excepts if any root element is unbound and thus not on the hardware graph def checkSynthesizable(target: Data, error_prelude: String): Unit = { - // This is called if we support autoIOWrap - def elementOfIO(element: Element): Boolean = { - element._parent match { - case None => false - case Some(x: Module) => { - // Have we defined the IO ports for this module? If not, do so now. - if (!x.ioDefined) { - x.computePorts - element.binding match { - case SynthesizableBinding() => true - case _ => false - } - } else { - // io.flatten eliminates Clock elements, so we need to use io.allElements - val ports = x.io.allElements - val isIOElement = ports.contains(element) || element == x.clock || element == x.reset - isIOElement - } - } - } - } - - // Diagnose a binding error caused by a missing IO() wrapper. - // element is the element triggering the binding error. - // Returns true if the element is a member of the module's io but ioDefined is false. - def isMissingIOWrapper(element: Element): Boolean = { - element._parent match { - case None => false - case Some(x: Module) => { - // If the IO() wrapper has been executed, it isn't missing. - if (x.ioDefined) { - false - } else { - // TODO: We should issue the message only once, and if we get here, - // we know the wrapper is missing, whether or not the element is a member of io. - // But if it's not an io element, we want to issue the complementary "unbound" error. - // Revisit this when we collect error messages instead of throwing exceptions. - // The null test below is due to the fact that we may be evaluating the arguments - // of the IO() wrapper itself. - (x.io != null) && x.io.flatten.contains(element) - } - } - } - } - try walkToBinding( target, - element => element.binding match { - case SynthesizableBinding() => {} // OK - case binding => - // The following kludge is an attempt to provide backward compatibility - // It should be done at at higher level. - if ((forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) { - // Generate a better error message if this is a result of a missing IO() wrapper. - if (isMissingIOWrapper(element)) { - throw MissingIOWrapperException - } else { - throw NotSynthesizableException + element => { + // Compatibility mode to automatically wrap ports in IO + // TODO: remove me, perhaps by removing Bindings checks from compatibility mode + element._parent match { + case Some(x: BaseModule) => x._autoWrapPorts + case _ => + } + // Actual binding check + element.binding match { + case SynthesizableBinding() => // OK + case binding => { + // Attempt to diagnose common bindings issues, like forgot to wrap IO(...) + element._parent match { + case Some(x: LegacyModule) => + // null check in case we try to access io before it is defined + if ((x.io != null) && (x.io.flatten contains element)) { + throw MissingIOWrapperException + } + case _ => } - } else { - Binding.bind(element, PortBinder(element._parent.get), "Error: IO") + // Fallback generic exception + throw NotSynthesizableException } + } } ) catch { @@ -190,7 +152,7 @@ object Binding { // Location refers to 'where' in the Module hierarchy this lives sealed trait Binding { - def location: Option[Module] + def location: Option[BaseModule] def direction: Option[Direction] } @@ -202,7 +164,7 @@ sealed trait UnconstrainedBinding extends Binding { // A constrained binding can only be read/written by specific modules // Location will track where this Module is sealed trait ConstrainedBinding extends Binding { - def enclosure: Module + def enclosure: BaseModule def location = Some(enclosure) } @@ -224,19 +186,19 @@ sealed trait SynthesizableBinding extends Binding case class LitBinding() // will eventually have literal info extends SynthesizableBinding with UnconstrainedBinding with UndirectionedBinding -case class MemoryPortBinding(enclosure: Module) +case class MemoryPortBinding(enclosure: UserModule) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding // TODO(twigg): Ops between unenclosed nodes can also be unenclosed // However, Chisel currently binds all op results to a module -case class OpBinding(enclosure: Module) +case class OpBinding(enclosure: UserModule) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding -case class PortBinding(enclosure: Module, direction: Option[Direction]) +case class PortBinding(enclosure: BaseModule, direction: Option[Direction]) extends SynthesizableBinding with ConstrainedBinding -case class RegBinding(enclosure: Module) +case class RegBinding(enclosure: UserModule) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding -case class WireBinding(enclosure: Module) +case class WireBinding(enclosure: UserModule) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index dd3a2e8b..a8a96946 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -1047,7 +1047,7 @@ final class Analog private (width: Width) extends Element(width) { // Used to enforce single bulk connect of Analog types, multi-attach is still okay // Note that this really means 1 bulk connect per Module because a port can // be connected in the parent module as well - private[core] val biConnectLocs = mutable.Map.empty[Module, SourceInfo] + private[core] val biConnectLocs = mutable.Map.empty[UserModule, SourceInfo] // Define setter/getter pairing // Analog can only be bound to Ports and Wires (and Unbound) diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index fa81a4a5..7a1394bb 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -5,7 +5,7 @@ package chisel3.core import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.throwException -import chisel3.internal.sourceinfo.SourceInfo +import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} // TODO: remove this once we have CompileOptions threaded through the macro system. import chisel3.core.ExplicitCompileOptions.NotStrict @@ -17,6 +17,86 @@ case class StringParam(value: String) extends Param /** Unquoted String */ case class RawParam(value: String) extends Param +abstract class BaseBlackBox extends BaseModule + +/** 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. + * + * A variant of BlackBox, this has a more consistent naming scheme in allowing + * multiple top-level IO and does not drop the top prefix. + * + * @example + * Some design require a differential input clock to clock the all design. + * With the xilinx FPGA for example, a Verilog template named IBUFDS must be + * integrated to use differential input: + * {{{ + * IBUFDS #(.DIFF_TERM("TRUE"), + * .IOSTANDARD("DEFAULT")) ibufds ( + * .IB(ibufds_IB), + * .I(ibufds_I), + * .O(ibufds_O) + * ); + * }}} + * + * To instantiate it, a BlackBox can be used like following: + * {{{ + * import chisel3._ + * import chisel3.experimental._ + * + * // Example with Xilinx differential buffer IBUFDS + * class IBUFDS extends ExtModule(Map("DIFF_TERM" -> "TRUE", // Verilog parameters + * "IOSTANDARD" -> "DEFAULT" + * )) { + * val O = IO(Output(Clock())) + * val I = IO(Input(Clock())) + * val IB = IO(Input(Clock())) + * } + * }}} + * @note The parameters API is experimental and may change + */ +abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Param]) extends BaseBlackBox { + private[core] override def generateComponent(): Component = { + require(!_closed, "Can't generate module more than once") + _closed = true + + val names = nameIds(classOf[ExtModule]) + + // Name ports based on reflection + for (port <- getModulePorts) { + require(names.contains(port), s"Unable to name port $port in $this") + port.setRef(ModuleIO(this, _namespace.name(names(port)))) + } + + // All suggestions are in, force names to every node. + // While BlackBoxes are not supposed to have an implementation, we still need to call + // _onModuleClose on all nodes (for example, Aggregates use it for recursive naming). + for (id <- getIds) { + id.forceName(default="_T", _namespace) + id._onModuleClose + } + + val firrtlPorts = for (port <- getModulePorts) yield { + // Port definitions need to know input or output at top-level. + // By FIRRTL semantics, 'flipped' becomes an Input + val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output + Port(port, direction) + } + + val component = DefBlackBox(this, name, firrtlPorts, params) + _component = Some(component) + component + } + + private[core] def initializeInParent() { + implicit val sourceInfo = UnlocatableSourceInfo + + for (x <- getModulePorts) { + pushCommand(DefInvalid(sourceInfo, x.ref)) + } + } +} + /** 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. @@ -52,45 +132,56 @@ case class RawParam(value: String) extends Param * }}} * @note The parameters API is experimental and may change */ -abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param]) extends Module { +abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param]) extends BaseBlackBox { + def io: Record + + // Allow access to bindings from the compatibility package + protected def _ioPortBound() = portsContains(io) + + private[core] override def generateComponent(): Component = { + _autoWrapPorts() // pre-IO(...) compatibility hack - // 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 - // TODO(twigg): ? Really, overrides are bad, should extend BaseModule.... - override private[core] def ports = io.elements.toSeq + // Restrict IO to just io, clock, and reset + require(io != null, "BlackBox must have io") + require(portsContains(io), "BlackBox must have io wrapped in IO(...)") + require(portsSize == 1, "BlackBox must only have io as IO") - // Do not do reflective naming of internal signals, just name io - override private[core] def setRefs(): this.type = { + require(!_closed, "Can't generate module more than once") + _closed = true + + val namedPorts = io.elements.toSeq // setRef is not called on the actual io. // There is a risk of user improperly attempting to connect directly with io // Long term solution will be to define BlackBox IO differently as part of // it not descending from the (current) Module - for ((name, port) <- ports) { + for ((name, port) <- namedPorts) { port.setRef(ModuleIO(this, _namespace.name(name))) } + // We need to call forceName and onModuleClose on all of the sub-elements // of the io bundle, but NOT on the io bundle itself. // Doing so would cause the wrong names to be assigned, since their parent // is now the module itself instead of the io bundle. - for (id <- _ids; if id ne io) { + for (id <- getIds; if id ne io) { id.forceName(default="_T", _namespace) id._onModuleClose } - this - } - // Don't setup clock, reset - // Cann't invalide io in one bunch, must invalidate each part separately - override private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = _parent match { - case Some(p) => { - // Just init instance inputs - for((_,port) <- ports) pushCommand(DefInvalid(sourceInfo, port.ref)) - this + val firrtlPorts = for ((_, port) <- namedPorts) yield { + // Port definitions need to know input or output at top-level. + // By FIRRTL semantics, 'flipped' becomes an Input + val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output + Port(port, direction) } - case None => this + + val component = DefBlackBox(this, name, firrtlPorts, params) + _component = Some(component) + component } - // Using null is horrible but these signals SHOULD NEVER be used: - override val clock = null - override val reset = null + private[core] def initializeInParent() { + for ((_, port) <- io.elements) { + pushCommand(DefInvalid(UnlocatableSourceInfo, port.ref)) + } + } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala b/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala index 73573bb1..015629e5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala @@ -18,7 +18,7 @@ case class ChiselAnnotation(component: InstanceId, transformClass: Class[_ <: Tr def toFirrtl: Annotation = { val circuitName = CircuitName(component.pathName.split("""\.""").head) component match { - case m: Module => + case m: BaseModule => Annotation( ModuleName(m.name, circuitName), transformClass, value) case _ => diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala index 482c1566..803e6c0f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala @@ -12,8 +12,6 @@ trait CompileOptions { val connectFieldsMustMatch: Boolean // When creating an object that takes a type argument, the argument must be unbound (a pure type). val declaredTypeMustBeUnbound: Boolean - // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. - val requireIOWrap: Boolean // If a connection operator fails, don't try the connection with the operands (source and sink) reversed. val dontTryConnectionsSwapped: Boolean // If connection directionality is not explicit, do not use heuristics to attempt to determine it. @@ -44,8 +42,6 @@ object ExplicitCompileOptions { val connectFieldsMustMatch: Boolean, // When creating an object that takes a type argument, the argument must be unbound (a pure type). val declaredTypeMustBeUnbound: Boolean, - // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. - val requireIOWrap: Boolean, // If a connection operator fails, don't try the connection with the operands (source and sink) reversed. val dontTryConnectionsSwapped: Boolean, // If connection directionality is not explicit, do not use heuristics to attempt to determine it. @@ -63,7 +59,6 @@ object ExplicitCompileOptions { implicit val NotStrict = new CompileOptionsClass ( connectFieldsMustMatch = false, declaredTypeMustBeUnbound = false, - requireIOWrap = false, dontTryConnectionsSwapped = false, dontAssumeDirectionality = false, deprecateOldDirectionMethods = false, @@ -75,7 +70,6 @@ object ExplicitCompileOptions { implicit val Strict = new CompileOptionsClass ( connectFieldsMustMatch = true, declaredTypeMustBeUnbound = true, - requireIOWrap = true, dontTryConnectionsSwapped = true, dontAssumeDirectionality = true, deprecateOldDirectionMethods = true, diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 556f2aeb..c17672ff 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -200,7 +200,7 @@ abstract class Data extends HasId { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { - MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) + MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedUserModule) } catch { case MonoConnect.MonoConnectException(message) => throwException( @@ -216,7 +216,7 @@ abstract class Data extends HasId { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { - BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) + BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedUserModule) } catch { case BiConnect.BiConnectException(message) => throwException( @@ -374,7 +374,7 @@ object Wire { val x = t.chiselCloneType // Bind each element of x to being a Wire - Binding.bind(x, WireBinder(Builder.forcedModule), "Error: t") + Binding.bind(x, WireBinder(Builder.forcedUserModule), "Error: t") pushCommand(DefWire(sourceInfo, x)) pushCommand(DefInvalid(sourceInfo, x.ref)) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index a48af15a..006670e7 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -95,7 +95,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi t.chiselCloneType, Node(this), dir, i.ref, Node(Builder.forcedClock)) ).id // Bind each element of port to being a MemoryPort - Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t") + Binding.bind(port, MemoryPortBinder(Builder.forcedUserModule), "Error: Fresh t") port } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index b838eb05..4c4c0c01 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -2,13 +2,16 @@ package chisel3.core -import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.{ArrayBuffer, HashMap} +import scala.collection.JavaConversions._ import scala.language.experimental.macros + +import java.util.IdentityHashMap + import chisel3.internal._ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ -import chisel3.internal.firrtl.{Command => _, _} -import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} +import chisel3.internal.sourceinfo.{InstTransform, SourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -18,19 +21,16 @@ object Module { * * @return the input module `m` with Chisel metadata properly set */ - def apply[T <: Module](bc: => T): T = macro InstTransform.apply[T] - - def do_apply[T <: Module](bc: => T)(implicit sourceInfo: SourceInfo): T = { - // Don't generate source info referencing parents inside a module, sincce this interferes with - // module de-duplication in FIRRTL emission. - val childSourceInfo = UnlocatableSourceInfo + def apply[T <: BaseModule](bc: => T): T = macro InstTransform.apply[T] + def do_apply[T <: BaseModule](bc: => T)(implicit sourceInfo: SourceInfo): T = { if (Builder.readyForModuleConstr) { throwException("Error: Called Module() twice without instantiating a Module." + sourceInfo.makeMessage(" See " + _)) } Builder.readyForModuleConstr = true - val parent: Option[Module] = Builder.currentModule + + val parent = Builder.currentModule val whenDepth: Int = Builder.whenDepth val clockAndReset: Option[ClockAndReset] = Builder.currentClockAndReset @@ -39,8 +39,7 @@ object Module { // - unset readyForModuleConstr // - reset whenDepth to 0 // - set currentClockAndReset - val m = bc.setRefs() - m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs + val module: T = bc // bc is actually evaluated here if (Builder.whenDepth != 0) { throwException("Internal Error! When depth is != 0, this should not be possible") @@ -54,23 +53,15 @@ object Module { Builder.whenDepth = whenDepth Builder.currentClockAndReset = clockAndReset // Back to clock and reset scope - val ports = m.computePorts - // 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) + val component = module.generateComponent() Builder.components += component - // Avoid referencing 'parent' in top module + + // Handle connections at enclosing scope if(!Builder.currentModule.isEmpty) { - pushCommand(DefInstance(sourceInfo, m, ports)) - m.setupInParent(childSourceInfo) + pushCommand(DefInstance(sourceInfo, module, component.ports)) + module.initializeInParent() } - m + module } /** Returns the implicit Clock */ @@ -79,141 +70,94 @@ object Module { def reset: Bool = Builder.forcedReset } -/** Abstract base class for Modules, which behave much like Verilog modules. - * These may contain both logic and state which are written in the Module - * body (constructor). - * - * @note Module instantiations must be wrapped in a Module() call. +/** Abstract base class for Modules, an instantiable organizational unit for RTL. */ -abstract class Module( - override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) - (implicit moduleCompileOptions: CompileOptions) -extends HasId { - // _clock and _reset can be clock and reset in these 2ary constructors - // once chisel2 compatibility issues are resolved - def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), None)(moduleCompileOptions) - def this(_reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(None, Option(_reset))(moduleCompileOptions) - def this(_clock: Clock, _reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), Option(_reset))(moduleCompileOptions) - - // This function binds the iodef as a port in the hardware graph - private[chisel3] def Port[T<:Data](iodef: T): iodef.type = { - // Bind each element of the iodef to being a Port - Binding.bind(iodef, PortBinder(this), "Error: iodef") - iodef - } - - def annotate(annotation: ChiselAnnotation): Unit = { - Builder.annotations += annotation +// TODO: seal this? +abstract class BaseModule extends HasId { + // + // Builder Internals - this tracks which Module RTL construction belongs to. + // + if (!Builder.readyForModuleConstr) { + throwException("Error: attempted to instantiate a Module without wrapping it in Module().") } + readyForModuleConstr = false - private[core] var ioDefined: Boolean = false - - /** - * This must wrap the datatype used to set the io field of any Module. - * i.e. All concrete modules must have defined io in this form: - * [lazy] val io[: io type] = IO(...[: io type]) - * - * Items in [] are optional. - * - * The granted iodef WILL NOT be cloned (to allow for more seamless use of - * anonymous Bundles in the IO) and thus CANNOT have been bound to any logic. - * This will error if any node is bound (e.g. due to logic in a Bundle - * constructor, which is considered improper). - * - * TODO(twigg): Specifically walk the Data definition to call out which nodes - * are problematic. - */ - def IO[T<:Data](iodef: T): iodef.type = { - require(!ioDefined, "Another IO definition for this module was already declared!") - ioDefined = true + Builder.currentModule = Some(this) + Builder.whenDepth = 0 - Port(iodef) - } + // + // Module Construction Internals + // + protected var _closed = false // Fresh Namespace because in Firrtl, Modules namespaces are disjoint with the global namespace private[core] val _namespace = Namespace.empty - private[chisel3] val _commands = ArrayBuffer[Command]() - private[core] val _ids = ArrayBuffer[HasId]() - Builder.currentModule = Some(this) - Builder.whenDepth = 0 - if (!Builder.readyForModuleConstr) { - throwException("Error: attempted to instantiate a Module without wrapping it in Module().") + private val _ids = ArrayBuffer[HasId]() + private[chisel3] def addId(d: HasId) { + require(!_closed, "Can't write to module after module close") + _ids += d + } + protected def getIds = { + require(_closed, "Can't get ids before module close") + _ids.toSeq } - readyForModuleConstr = false - /** Desired name of this module. */ + private val _ports = new ArrayBuffer[Data]() + // getPorts unfortunately already used for tester compatibility + protected def getModulePorts = { + require(_closed, "Can't get ports before module close") + _ports.toSeq + } + + // These methods allow checking some properties of ports before the module is closed, + // mainly for compatibility purposes. + protected def portsContains(elem: Data): Boolean = _ports contains elem + protected def portsSize: Int = _ports.size + + /** Generates the FIRRTL Component (Module or Blackbox) of this Module. + * Also closes the module so no more construction can happen inside. + */ + private[core] def generateComponent(): Component + + /** Sets up this module in the parent context + */ + private[core] def initializeInParent() + + // + // Chisel Internals + // + /** Desired name of this module. Override this to give this module a custom, perhaps parametric, + * name. + */ def desiredName = this.getClass.getName.split('.').last /** Legalized name of this module. */ final val name = Builder.globalNamespace.name(desiredName) - /** Keep component for signal names */ - private[chisel3] var _component: Option[Component] = None - - /** Signal name (for simulation). */ - override def instanceName = - if (_parent == None) name else _component match { - case None => getRef.name - case Some(c) => getRef fullName c - } - - /** IO for this Module. At the Scala level (pre-FIRRTL transformations), - * connections in and out of a Module may only go through `io` elements. + /** Called at the Module.apply(...) level after this Module has finished elaborating. + * Returns a map of nodes -> names, for named nodes. + * + * Helper method. */ - def io: Record - val clock = Port(Input(Clock())) - val reset = Port(Input(Bool())) - - // Setup ClockAndReset - Builder.currentClockAndReset = Some(ClockAndReset(clock, reset)) - - private[chisel3] def addId(d: HasId) { _ids += d } - - private[core] def ports: Seq[(String,Data)] = Vector( - ("clock", clock), ("reset", reset), ("io", io) - ) - - private[core] def computePorts: Seq[firrtl.Port] = { - // If we're auto-wrapping IO definitions, do so now. - if (!(compileOptions.requireIOWrap || ioDefined)) { - IO(io) - } - for ((name, port) <- ports) yield { - // Port definitions need to know input or output at top-level. - // By FIRRTL semantics, 'flipped' becomes an Input - val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output - firrtl.Port(port, direction) - } - } - - private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { - _parent match { - case Some(p) => { - pushCommand(DefInvalid(sourceInfo, io.ref)) // init instance inputs - clock := override_clock.getOrElse(Builder.forcedClock) - reset := override_reset.getOrElse(Builder.forcedReset) - this + protected def nameIds(rootClass: Class[_]): HashMap[HasId, String] = { + val names = new HashMap[HasId, String]() + + def name(node: HasId, name: String) { + // First name takes priority, like suggestName + // TODO: DRYify with suggestName + if (!names.contains(node)) { + names.put(node, name) } - case None => this - } - } - - private[core] def setRefs(): this.type = { - for ((name, port) <- ports) { - port.setRef(ModuleIO(this, _namespace.name(name))) } /** Recursively suggests names to supported "container" classes * Arbitrary nestings of supported classes are allowed so long as the * innermost element is of type HasId - * Currently supported: - * - Iterable - * - Option - * (Note that Map is Iterable[Tuple2[_,_]] and thus excluded) + * (Note: Map is Iterable[Tuple2[_,_]] and thus excluded) */ def nameRecursively(prefix: String, nameMe: Any): Unit = nameMe match { - case (id: HasId) => id.suggestName(prefix) + case (id: HasId) => name(id, prefix) case Some(elt) => nameRecursively(prefix, elt) case (iter: Iterable[_]) if iter.hasDefiniteSize => for ((elt, i) <- iter.zipWithIndex) { @@ -221,27 +165,75 @@ extends HasId { } case _ => // Do nothing } + /** Scala generates names like chisel3$util$Queue$$ram for private vals * This extracts the part after $$ for names like this and leaves names * without $$ unchanged */ def cleanName(name: String): String = name.split("""\$\$""").lastOption.getOrElse(name) - for (m <- getPublicFields(classOf[Module])) { + + for (m <- getPublicFields(rootClass)) { nameRecursively(cleanName(m.getName), m.invoke(this)) } - // For Module instances we haven't named, suggest the name of the Module - _ids foreach { - case m: Module => m.suggestName(m.desiredName) - case _ => - } + names + } + + /** Compatibility function. Allows Chisel2 code which had ports without the IO wrapper to + * compile under Bindings checks. Does nothing in non-compatibility mode. + * + * Should NOT be used elsewhere. This API will NOT last. + * + * TODO: remove this, perhaps by removing Bindings checks in compatibility mode. + */ + def _autoWrapPorts() {} - // All suggestions are in, force names to every node. - _ids.foreach(_.forceName(default="_T", _namespace)) - _ids.foreach(_._onModuleClose) - this + // + // BaseModule User API functions + // + protected def annotate(annotation: ChiselAnnotation): Unit = { + Builder.annotations += annotation } - // For debuggers/testers - lazy val getPorts = computePorts - val compileOptions = moduleCompileOptions + + /** + * This must wrap the datatype used to set the io field of any Module. + * i.e. All concrete modules must have defined io in this form: + * [lazy] val io[: io type] = IO(...[: io type]) + * + * Items in [] are optional. + * + * The granted iodef WILL NOT be cloned (to allow for more seamless use of + * anonymous Bundles in the IO) and thus CANNOT have been bound to any logic. + * This will error if any node is bound (e.g. due to logic in a Bundle + * constructor, which is considered improper). + * + * Also registers a Data as a port, also performing bindings. Cannot be called once ports are + * requested (so that all calls to ports will return the same information). + * Internal API. + * + * TODO(twigg): Specifically walk the Data definition to call out which nodes + * are problematic. + */ + protected def IO[T<:Data](iodef: T): iodef.type = { + require(!_closed, "Can't add more ports after module close") + // Bind each element of the iodef to being a Port + Binding.bind(iodef, PortBinder(this), "Error: iodef") + _ports += iodef + iodef + } + + // + // Internal Functions + // + + /** Keep component for signal names */ + private[chisel3] var _component: Option[Component] = None + + /** Signal name (for simulation). */ + override def instanceName = + if (_parent == None) name else _component match { + case None => getRef.name + case Some(c) => getRef fullName c + } + } diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 9511fdc9..60f500cd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -55,7 +55,7 @@ object MonoConnect { * during the recursive decent and then rethrow them with extra information added. * This gives the user a 'path' to where in the connections things went wrong. */ - def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Data, source: Data, context_mod: Module): Unit = + def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Data, source: Data, context_mod: UserModule): Unit = (sink, source) match { // Handle element case (root case) case (sink_e: Element, source_e: Element) => { @@ -102,12 +102,12 @@ object MonoConnect { // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. - def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Element, source: Element, context_mod: Module): Unit = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Element, source: Element, context_mod: UserModule): Unit = { import Direction.{Input, Output} // Using extensively so import these // If source has no location, assume in context module // This can occur if is a literal, unbound will error previously - val sink_mod: Module = sink.binding.location.getOrElse(throw UnwritableSinkException) - val source_mod: Module = source.binding.location.getOrElse(context_mod) + val sink_mod: BaseModule = sink.binding.location.getOrElse(throw UnwritableSinkException) + val source_mod: BaseModule = source.binding.location.getOrElse(context_mod) val sink_direction: Option[Direction] = sink.binding.direction val source_direction: Option[Direction] = source.binding.direction diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala index 81210f45..2052e95a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -64,6 +64,7 @@ object printf { // scalastyle:ignore object.name val clock = Builder.forcedClock pushCommand(Printf(sourceInfo, Node(clock), pable)) } + private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = printfWithoutReset(Printable.pack(fmt, data:_*)) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 715bdd70..12d0a939 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -22,7 +22,7 @@ object Reg { val reg = t.chiselCloneType val clock = Node(Builder.forcedClock) - Binding.bind(reg, RegBinder(Builder.forcedModule), "Error: t") + Binding.bind(reg, RegBinder(Builder.forcedUserModule), "Error: t") pushCommand(DefReg(sourceInfo, reg, clock)) reg } @@ -90,7 +90,7 @@ object RegInit { val clock = Node(Builder.forcedClock) val reset = Node(Builder.forcedReset) - Binding.bind(reg, RegBinder(Builder.forcedModule), "Error: t") + Binding.bind(reg, RegBinder(Builder.forcedUserModule), "Error: t") Binding.checkSynthesizable(init, s"'init' ($init)") pushCommand(DefRegInit(sourceInfo, reg, clock, reset, init.ref)) reg diff --git a/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala b/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala new file mode 100644 index 00000000..916ab119 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala @@ -0,0 +1,177 @@ +// See LICENSE for license details. + +package chisel3.core + +import scala.collection.mutable.{ArrayBuffer, HashMap} +import scala.collection.JavaConversions._ +import scala.language.experimental.macros + +import chisel3.internal._ +import chisel3.internal.Builder._ +import chisel3.internal.firrtl._ +import chisel3.internal.firrtl.{Command => _, _} +import chisel3.internal.sourceinfo.UnlocatableSourceInfo + +/** Abstract base class for Modules that contain Chisel RTL. + */ +abstract class UserModule(implicit moduleCompileOptions: CompileOptions) + extends BaseModule { + // + // RTL construction internals + // + private val _commands = ArrayBuffer[Command]() + private[chisel3] def addCommand(c: Command) { + require(!_closed, "Can't write to module after module close") + _commands += c + } + protected def getCommands = { + require(_closed, "Can't get commands before module close") + _commands.toSeq + } + + // + // Other Internal Functions + // + // For debuggers/testers, TODO: refactor out into proper public API + private var _firrtlPorts: Option[Seq[firrtl.Port]] = None + lazy val getPorts = _firrtlPorts.get + + val compileOptions = moduleCompileOptions + + private[core] override def generateComponent(): Component = { + require(!_closed, "Can't generate module more than once") + _closed = true + + val names = nameIds(classOf[UserModule]) + + // Ports get first naming priority, since they are part of a Module's IO spec + for (port <- getModulePorts) { + require(names.contains(port), s"Unable to name port $port in $this") + port.setRef(ModuleIO(this, _namespace.name(names(port)))) + } + + // Then everything else gets named + for ((node, name) <- names) { + node.suggestName(name) + } + + // All suggestions are in, force names to every node. + for (id <- getIds) { + id match { + case id: BaseModule => id.forceName(default=id.desiredName, _namespace) + case id => id.forceName(default="_T", _namespace) + } + id._onModuleClose + } + + val firrtlPorts = for (port <- getModulePorts) yield { + // Port definitions need to know input or output at top-level. 'flipped' means Input. + val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output + firrtl.Port(port, direction) + } + _firrtlPorts = Some(firrtlPorts) + + // Generate IO invalidation commands to initialize outputs as unused + val invalidateCommands = getModulePorts map {port => DefInvalid(UnlocatableSourceInfo, port.ref)} + + val component = DefModule(this, name, firrtlPorts, invalidateCommands ++ getCommands) + _component = Some(component) + component + } + + // There is no initialization to be done by default. + private[core] def initializeInParent() {} +} + +/** Abstract base class for Modules, which behave much like Verilog modules. + * These may contain both logic and state which are written in the Module + * body (constructor). + * + * @note Module instantiations must be wrapped in a Module() call. + */ +abstract class ImplicitModule(implicit moduleCompileOptions: CompileOptions) + extends UserModule { + // Implicit clock and reset pins + val clock = IO(Input(Clock())) + val reset = IO(Input(Bool())) + + // Setup ClockAndReset + Builder.currentClockAndReset = Some(ClockAndReset(clock, reset)) + + private[core] override def initializeInParent() { + implicit val sourceInfo = UnlocatableSourceInfo + + for (port <- getModulePorts) { + pushCommand(DefInvalid(sourceInfo, port.ref)) + } + + clock := Builder.forcedClock + reset := Builder.forcedReset + } +} + +/** Legacy Module class that restricts IOs to just io, clock, and reset, and provides a constructor + * for threading through explicit clock and reset. + * + * While this class isn't planned to be removed anytime soon (there are benefits to restricting + * IO), the clock and reset constructors will be phased out. Recommendation is to wrap the module + * in a withClock/withReset/withClockAndReset block, or directly hook up clock or reset IO pins. + */ +abstract class LegacyModule( + override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) + (implicit moduleCompileOptions: CompileOptions) + extends ImplicitModule { + // _clock and _reset can be clock and reset in these 2ary constructors + // once chisel2 compatibility issues are resolved + def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), None)(moduleCompileOptions) + def this(_reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(None, Option(_reset))(moduleCompileOptions) + def this(_clock: Clock, _reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), Option(_reset))(moduleCompileOptions) + + // IO for this Module. At the Scala level (pre-FIRRTL transformations), + // connections in and out of a Module may only go through `io` elements. + def io: Record + + // Allow access to bindings from the compatibility package + protected def _ioPortBound() = portsContains(io) + + protected override def nameIds(rootClass: Class[_]): HashMap[HasId, String] = { + val names = super.nameIds(rootClass) + + // Allow IO naming without reflection + names.put(io, "io") + names.put(clock, "clock") + names.put(reset, "reset") + + names + } + + private[core] override def generateComponent(): Component = { + _autoWrapPorts() // pre-IO(...) compatibility hack + + // Restrict IO to just io, clock, and reset + require(io != null, "Module must have io") + require(portsContains(io), "Module must have io wrapped in IO(...)") + require((portsContains(clock)) && (portsContains(reset)), "Internal error, module did not have clock or reset as IO") + require(portsSize == 3, "Module must only have io, clock, and reset as IO") + + super.generateComponent() + } + + private[core] override def initializeInParent() { + // Don't generate source info referencing parents inside a module, since this interferes with + // module de-duplication in FIRRTL emission. + implicit val sourceInfo = UnlocatableSourceInfo + + pushCommand(DefInvalid(sourceInfo, io.ref)) + + override_clock match { + case Some(override_clock) => clock := override_clock + case _ => clock := Builder.forcedClock + } + + override_reset match { + case Some(override_reset) => reset := override_reset + case _ => reset := Builder.forcedReset + } + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index e0cbf302..73556750 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -70,7 +70,7 @@ trait InstanceId { private[chisel3] trait HasId extends InstanceId { private[chisel3] def _onModuleClose: Unit = {} // scalastyle:ignore method.name - private[chisel3] val _parent: Option[Module] = Builder.currentModule + private[chisel3] val _parent: Option[BaseModule] = Builder.currentModule _parent.foreach(_.addId(this)) private[chisel3] val _id: Long = Builder.idGen.next @@ -148,7 +148,7 @@ private[chisel3] class DynamicContext() { val globalNamespace = Namespace.empty val components = ArrayBuffer[Component]() val annotations = ArrayBuffer[ChiselAnnotation]() - var currentModule: Option[Module] = None + var currentModule: Option[BaseModule] = None // Set by object Module.apply before calling class Module constructor // Used to distinguish between no Module() wrapping, multiple wrappings, and rewrapping var readyForModuleConstr: Boolean = false @@ -170,17 +170,24 @@ private[chisel3] object Builder { def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations def namingStack: internal.naming.NamingStack = dynamicContext.namingStack - def currentModule: Option[Module] = dynamicContext.currentModule - def currentModule_=(target: Option[Module]): Unit = { + def currentModule: Option[BaseModule] = dynamicContext.currentModule + def currentModule_=(target: Option[BaseModule]): Unit = { dynamicContext.currentModule = target } - def forcedModule: Module = currentModule match { + def forcedModule: BaseModule = currentModule match { case Some(module) => module case None => throwException( "Error: Not in a Module. Likely cause: Missed Module() wrap or bare chisel API call." // A bare api call is, e.g. calling Wire() from the scala console). ) } + def forcedUserModule: UserModule = currentModule match { + case Some(module: UserModule) => module + case _ => throwException( + "Error: Not in a UserModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox." + // A bare api call is, e.g. calling Wire() from the scala console). + ) + } def readyForModuleConstr: Boolean = dynamicContext.readyForModuleConstr def readyForModuleConstr_=(target: Boolean): Unit = { dynamicContext.readyForModuleConstr = target @@ -203,15 +210,12 @@ 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 match { - case _: BlackBox => throwException("Cannot add hardware to a BlackBox") - case m => m._commands += c - } + forcedUserModule.addCommand(c) c } def pushOp[T <: Data](cmd: DefPrim[T]): T = { // Bind each element of the returned Data to being a Op - Binding.bind(cmd.id, OpBinder(forcedModule), "Error: During op creation, fresh result") + Binding.bind(cmd.id, OpBinder(forcedUserModule), "Error: During op creation, fresh result") pushCommand(cmd).id } @@ -230,7 +234,7 @@ private[chisel3] object Builder { throwException(m) } - def build[T <: Module](f: => T): Circuit = { + def build[T <: UserModule](f: => T): Circuit = { dynamicContextVar.withValue(Some(new DynamicContext())) { errors.info("Elaborating design...") val mod = f diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala index bba7c806..25a3ec2a 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala @@ -55,7 +55,7 @@ private[chisel3] class ErrorLog { private def findFirstUserFrame(stack: Array[StackTraceElement]): Option[StackTraceElement] = { def isUserCode(ste: StackTraceElement): Boolean = { def isUserModule(c: Class[_]): Boolean = - c != null && (c == classOf[Module] || isUserModule(c.getSuperclass)) + c != null && (c == classOf[UserModule] || isUserModule(c.getSuperclass)) isUserModule(Class.forName(ste.getClassName)) } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index bee72817..18df7f51 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -98,7 +98,7 @@ case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n } case class Ref(name: String) extends Arg -case class ModuleIO(mod: Module, name: String) extends Arg { +case class ModuleIO(mod: BaseModule, name: String) extends Arg { override def fullName(ctx: Component): String = if (mod eq ctx.id) name else s"${mod.getRef.name}.$name" } @@ -258,7 +258,7 @@ case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, 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 DefInstance(sourceInfo: SourceInfo, id: BaseModule, 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 @@ -269,11 +269,11 @@ case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command 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 id: BaseModule 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 DefModule(id: UserModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component +case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], params: Map[String, Param]) extends Component case class Circuit(name: String, components: Seq[Component], annotations: Seq[Annotation] = Seq.empty) |
