diff options
Diffstat (limited to 'chiselFrontend/src')
7 files changed, 65 insertions, 21 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 71de50f6..b7fd65a5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -166,8 +166,28 @@ object BiConnect { case (Some(Output), None) => issueConnectR2L(left, right) case (None, Some(Input)) => issueConnectR2L(left, right) - case (Some(Input), Some(Input)) => throw BothDriversException - case (Some(Output), Some(Output)) => throw NeitherDriverException + case (Some(Input), Some(Input)) => { + if (compileOptions.portDeterminesDirection) + (left.binding, right.binding) match { + case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException + case (PortBinding(_, _), _) => issueConnectL2R(left, right) + case (_, PortBinding(_, _)) => issueConnectR2L(left, right) + case _ => throw BothDriversException + } else { + throw BothDriversException + } + } + case (Some(Output), Some(Output)) => { + if (compileOptions.portDeterminesDirection) + (left.binding, right.binding) match { + case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException + case (PortBinding(_, _), _) => issueConnectR2L(left, right) + case (_, PortBinding(_, _)) => issueConnectL2R(left, right) + case _ => throw BothDriversException + } else { + throw BothDriversException + } + } case (None, None) => throw UnknownDriverException } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala index c7346dce..08c0519e 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala @@ -58,7 +58,8 @@ case class RegBinder(enclosure: Module) extends Binder[RegBinding] { def apply(in: UnboundBinding) = RegBinding(enclosure) } +// Notice how WireBinder uses the direction of the UnboundNode case class WireBinder(enclosure: Module) extends Binder[WireBinding] { - def apply(in: UnboundBinding) = WireBinding(enclosure) + def apply(in: UnboundBinding) = WireBinding(enclosure, in.direction) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index 75a80e4f..555ba4d5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -1,5 +1,7 @@ package chisel3.core +import chisel3.internal.Builder.compileOptions + /** * The purpose of a Binding is to indicate what type of hardware 'entity' a * specific Data's leaf Elements is actually bound to. All Data starts as being @@ -88,6 +90,8 @@ 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 (compileOptions.autoIOWrap && binder.isInstanceOf[PortBinder]) => case binding => throw AlreadyBoundException(binding.toString) } ) @@ -113,15 +117,24 @@ 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 is we support autoIOWrap - def elementOfIO(element: Data): Boolean = { + // This is called if we support autoIOWrap + def elementOfIO(element: Element): Boolean = { element._parent match { case None => false case Some(x: Module) => { - // 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 + // 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 + } } } } @@ -132,7 +145,7 @@ object Binding { case binding => // The following kludge is an attempt to provide backward compatibility // It should be done at at higher level. - if (!(autoIOWrap && elementOfIO(element))) + if (!(compileOptions.autoIOWrap && elementOfIO(element))) throw NotSynthesizableException else Binding.bind(element, PortBinder(element._parent.get), "Error: IO") @@ -142,8 +155,6 @@ object Binding { case BindingException(message) => throw BindingException(s"$error_prelude$message") } } - // This should be configure by options in Driver. - private[chisel3] var autoIOWrap = true } // Location refers to 'where' in the Module hierarchy this lives @@ -196,5 +207,5 @@ case class PortBinding(enclosure: Module, direction: Option[Direction]) case class RegBinding(enclosure: Module) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding -case class WireBinding(enclosure: Module) - extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding +case class WireBinding(enclosure: Module, direction: Option[Direction]) + extends SynthesizableBinding with ConstrainedBinding diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index bbed4d9f..450f5b58 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -4,13 +4,11 @@ package chisel3.core import scala.collection.mutable.ArrayBuffer import scala.language.experimental.macros - import chisel3.internal._ -import chisel3.internal.Builder.pushCommand -import chisel3.internal.Builder.dynamicContext +import chisel3.internal.Builder._ import chisel3.internal.firrtl._ -import chisel3.internal.firrtl.{Command, Component, DefInstance, DefInvalid, ModuleIO} -import chisel3.internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} +import chisel3.internal.firrtl.{Command => _, _} +import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -65,7 +63,7 @@ extends HasId { iodef } - private[this] var ioDefined: Boolean = false + private[core] var ioDefined: Boolean = false /** * This must wrap the datatype used to set the io field of any Module. @@ -115,6 +113,10 @@ extends HasId { private[core] def computePorts: Seq[firrtl.Port] = for((name, port) <- ports) yield { + // If we're auto-wrapping IO definitions, do so now. + if (compileOptions.autoIOWrap && name == "io" && !ioDefined) { + IO(port) + } // Port definitions need to know input or output at top-level. // By FIRRTL semantics, 'flipped' becomes an Input val direction = if(Data.isFlipped(port)) Direction.Input else Direction.Output diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index bf8e7e28..e0c95e80 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -118,6 +118,7 @@ object MonoConnect { // CURRENT MOD CURRENT MOD case (Some(Output), _) => issueConnect(sink, source) case (None, _) => issueConnect(sink, source) + case (_, None) if (compileOptions.internalConnectionToInputOk) => issueConnect(sink, source) case (Some(Input), _) => throw UnwritableSinkException } } @@ -134,6 +135,7 @@ object MonoConnect { case (Some(Output), Some(Output)) => issueConnect(sink, source) case (Some(Output), Some(Input)) => issueConnect(sink, source) case (_, None) => throw UnreadableSourceException + case (Some(Input), Some(Output)) if (compileOptions.tryConnectionsSwapped) => issueConnect(source, sink) case (Some(Input), _) => throw UnwritableSinkException } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index f5706833..6c357461 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -10,7 +10,9 @@ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) { - Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") + if (Builder.compileOptions.regTypeMustBeUnbound) { + Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") + } t.chiselCloneType } else if (next ne null) { next.cloneTypeWidth(Width()) diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index 12789855..b809b8fe 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -9,8 +9,14 @@ package chisel3.internal class CompileOptions(optionsMap: Map[String, String]) { // The default for settings related to "strictness". val strictDefault: String = optionsMap.getOrElse("strict", "false") + val looseDefault: String = (!(strictDefault.toBoolean)).toString // Should Bundle connections require a strict match of fields. // If true and the same fields aren't present in both source and sink, a MissingFieldException, // MissingLeftFieldException, or MissingRightFieldException will be thrown. val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean + val regTypeMustBeUnbound: Boolean = optionsMap.getOrElse("regTypeMustBeUnbound", strictDefault).toBoolean + val autoIOWrap: Boolean = optionsMap.getOrElse("autoIOWrap", looseDefault).toBoolean + val portDeterminesDirection: Boolean = optionsMap.getOrElse("portDeterminesDirection", looseDefault).toBoolean + val internalConnectionToInputOk: Boolean = optionsMap.getOrElse("internalConnectionToInputOk", looseDefault).toBoolean + val tryConnectionsSwapped: Boolean = optionsMap.getOrElse("tryConnectionsSwapped", looseDefault).toBoolean } |
