diff options
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/RawModule.scala')
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/RawModule.scala | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/RawModule.scala b/chiselFrontend/src/main/scala/chisel3/RawModule.scala new file mode 100644 index 00000000..14a7a584 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/RawModule.scala @@ -0,0 +1,255 @@ +// See LICENSE for license details. + +package chisel3.experimental + +import scala.collection.mutable.{ArrayBuffer, HashMap} +import scala.collection.JavaConversions._ +import scala.language.experimental.macros + +import chisel3._ +import chisel3.internal._ +import chisel3.internal.Builder._ +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.UnlocatableSourceInfo + +/** Abstract base class for Modules that contain Chisel RTL. + * This abstract base class is a user-defined module which does not include implicit clock and reset and supports + * multiple IO() declarations. + */ +abstract class RawModule(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[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = { + for (port <- getModulePorts) { + port.suggestedName.orElse(names.get(port)) match { + case Some(name) => + if (_namespace.contains(name)) { + Builder.error(s"""Unable to name port $port to "$name" in $this,""" + + " name is already taken by another port!") + } + port.setRef(ModuleIO(this, _namespace.name(name))) + case None => Builder.error(s"Unable to name port $port in $this, " + + "try making it a public field of the Module") + } + } + } + + + private[chisel3] override def generateComponent(): Component = { // scalastyle:ignore cyclomatic.complexity + require(!_closed, "Can't generate module more than once") + _closed = true + + val names = nameIds(classOf[RawModule]) + + // Ports get first naming priority, since they are part of a Module's IO spec + namePorts(names) + + // 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: MemBase[_] => id.forceName(default="_T", _namespace) + case id: Data => + if (id.isSynthesizable) { + id.topBinding match { + case OpBinding(_) | MemoryPortBinding(_) | PortBinding(_) | RegBinding(_) | WireBinding(_) => + id.forceName(default="_T", _namespace) + case _ => // don't name literals + } + } // else, don't name unbound types + } + id._onModuleClose + } + + val firrtlPorts = getModulePorts map { port: Data => + // Special case Vec to make FIRRTL emit the direction of its + // element. + // Just taking the Vec's specifiedDirection is a bug in cases like + // Vec(Flipped()), since the Vec's specifiedDirection is + // Unspecified. + val direction = port match { + case v: Vec[_] => v.specifiedDirection match { + case SpecifiedDirection.Input => SpecifiedDirection.Input + case SpecifiedDirection.Output => SpecifiedDirection.Output + case SpecifiedDirection.Flip => SpecifiedDirection.flip(v.sample_element.specifiedDirection) + case SpecifiedDirection.Unspecified => v.sample_element.specifiedDirection + } + case _ => port.specifiedDirection + } + + Port(port, direction) + } + _firrtlPorts = Some(firrtlPorts) + + // Generate IO invalidation commands to initialize outputs as unused, + // unless the client wants explicit control over their generation. + val invalidateCommands = { + if (!compileOptions.explicitInvalidate) { + getModulePorts map { port => DefInvalid(UnlocatableSourceInfo, port.ref) } + } else { + Seq() + } + } + val component = DefModule(this, name, firrtlPorts, invalidateCommands ++ getCommands) + _component = Some(component) + component + } + + private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = { + implicit val sourceInfo = UnlocatableSourceInfo + + if (!parentCompileOptions.explicitInvalidate) { + for (port <- getModulePorts) { + pushCommand(DefInvalid(sourceInfo, port.ref)) + } + } + } +} + +/** 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). + * This abstract base class includes an implicit clock and reset. + * + * @note Module instantiations must be wrapped in a Module() call. + */ +abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions) + extends RawModule { + // Implicit clock and reset pins + val clock: Clock = IO(Input(Clock())) + val reset: Reset = IO(Input(Bool())) + + // Setup ClockAndReset + Builder.currentClock = Some(clock) + Builder.currentReset = Some(reset) + + private[chisel3] override def initializeInParent(parentCompileOptions: CompileOptions): Unit = { + implicit val sourceInfo = UnlocatableSourceInfo + + super.initializeInParent(parentCompileOptions) + 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(implicit moduleCompileOptions: CompileOptions) + extends MultiIOModule { + // These are to be phased out + protected var override_clock: Option[Clock] = None + protected var override_reset: Option[Bool] = None + + // _clock and _reset can be clock and reset in these 2ary constructors + // once chisel2 compatibility issues are resolved + @chiselRuntimeDeprecated + @deprecated("Module constructor with override_clock and override_reset deprecated, use withClockAndReset", "chisel3") + def this(override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) + (implicit moduleCompileOptions: CompileOptions) = { + this() + this.override_clock = override_clock + this.override_reset = override_reset + } + + @chiselRuntimeDeprecated + @deprecated("Module constructor with override _clock deprecated, use withClock", "chisel3") + def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), None)(moduleCompileOptions) // scalastyle:ignore line.size.limit + + @chiselRuntimeDeprecated + @deprecated("Module constructor with override _reset deprecated, use withReset", "chisel3") + def this(_reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(None, Option(_reset))(moduleCompileOptions) // scalastyle:ignore line.size.limit + + @chiselRuntimeDeprecated + @deprecated("Module constructor with override _clock, _reset deprecated, use withClockAndReset", "chisel3") + def this(_clock: Clock, _reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), Option(_reset))(moduleCompileOptions) // scalastyle:ignore line.size.limit + + // 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 _compatIoPortBound() = portsContains(io)// scalastyle:ignore method.name + + 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[chisel3] override def namePorts(names: HashMap[HasId, String]): Unit = { + for (port <- getModulePorts) { + // This should already have been caught + if (!names.contains(port)) throwException(s"Unable to name port $port in $this") + val name = names(port) + port.setRef(ModuleIO(this, _namespace.name(name))) + } + } + + private[chisel3] override def generateComponent(): Component = { + _compatAutoWrapPorts() // 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") // scalastyle:ignore line.size.limit + require(portsSize == 3, "Module must only have io, clock, and reset as IO") + + super.generateComponent() + } + + private[chisel3] override def initializeInParent(parentCompileOptions: CompileOptions): Unit = { + // Don't generate source info referencing parents inside a module, since this interferes with + // module de-duplication in FIRRTL emission. + implicit val sourceInfo = UnlocatableSourceInfo + + if (!parentCompileOptions.explicitInvalidate) { + 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 + } + } +} |
