summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Wang2019-04-10 00:16:48 -0700
committeredwardcwang2019-04-19 13:02:34 -0700
commit32acdcf63ab74e7d47d7600f2211a72dd19280c3 (patch)
treee4ff45be46e9353a06814aeecb9207284df388e8
parentfe5571d5218149ead6df36c82485bce8e31a223f (diff)
Fix wrong directionality for Vec(Flipped())
Create Chisel IR Port() in a way that Converter is happy with. Also add more extensive test suite for future-proofing. Close #1063
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/RawModule.scala19
-rw-r--r--src/test/scala/chiselTests/Direction.scala106
2 files changed, 123 insertions, 2 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala b/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala
index 00e78295..b1cae1b7 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala
@@ -85,7 +85,24 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
id._onModuleClose
}
- val firrtlPorts = getModulePorts map {port => Port(port, port.specifiedDirection)}
+ 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,
diff --git a/src/test/scala/chiselTests/Direction.scala b/src/test/scala/chiselTests/Direction.scala
index 32e5a4fd..0b0807fd 100644
--- a/src/test/scala/chiselTests/Direction.scala
+++ b/src/test/scala/chiselTests/Direction.scala
@@ -127,7 +127,7 @@ class DirectionSpec extends ChiselPropSpec with Matchers {
}
}
- import chisel3.experimental.{MultiIOModule, DataMirror, Direction}
+ import chisel3.experimental.{MultiIOModule, DataMirror, Direction, RawModule}
import chisel3.core.SpecifiedDirection
property("Directions should be preserved through cloning and binding of Bundles") {
@@ -199,4 +199,108 @@ class DirectionSpec extends ChiselPropSpec with Matchers {
}
}.asInstanceOf[MultiIOModule]) // The cast works around weird reflection behavior (bug?)
}
+
+ property("Using Vec and Flipped together should calculate directions properly") {
+ class MyModule extends RawModule {
+ class MyBundle extends Bundle {
+ val a = Input(Bool())
+ val b = Output(Bool())
+ }
+
+ // Check all permutations of Vec and Flipped.
+ val regularVec = IO(Vec(1, new MyBundle))
+ regularVec <> DontCare
+ assert(DataMirror.directionOf(regularVec.head.a) == Direction.Input)
+ assert(DataMirror.directionOf(regularVec.head.b) == Direction.Output)
+
+ val vecFlipped = IO(Vec(1, Flipped(new MyBundle)))
+ vecFlipped <> DontCare
+ assert(DataMirror.directionOf(vecFlipped.head.a) == Direction.Output)
+ assert(DataMirror.directionOf(vecFlipped.head.b) == Direction.Input)
+
+ val flippedVec = IO(Flipped(Vec(1, new MyBundle)))
+ flippedVec <> DontCare
+ assert(DataMirror.directionOf(flippedVec.head.a) == Direction.Output)
+ assert(DataMirror.directionOf(flippedVec.head.b) == Direction.Input)
+
+ // Flipped(Vec(Flipped())) should be equal to non-flipped.
+ val flippedVecFlipped = IO(Flipped(Vec(1, Flipped(new MyBundle))))
+ flippedVecFlipped <> DontCare
+ assert(DataMirror.directionOf(flippedVecFlipped.head.a) == Direction.Input)
+ assert(DataMirror.directionOf(flippedVecFlipped.head.b) == Direction.Output)
+ }
+
+ val elaborated = Driver.elaborate(() => new MyModule)
+
+ val emitted: String = Driver.emit(elaborated)
+ val firrtl: String = Driver.toFirrtl(elaborated).serialize
+
+ // Check that emitted directions are correct.
+ Seq(emitted, firrtl).foreach { o => {
+ // Chisel Emitter formats spacing a little differently than the
+ // FIRRTL Emitter :-(
+ val s = o.replace("{flip a", "{ flip a")
+ assert(s.contains("output regularVec : { flip a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("input vecFlipped : { flip a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("input flippedVec : { flip a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("output flippedVecFlipped : { flip a : UInt<1>, b : UInt<1>}[1]"))
+ } }
+ }
+
+ property("Vec with Input/Output should calculate directions properly") {
+ class MyModule extends RawModule {
+ class MyBundle extends Bundle {
+ val a = Input(Bool())
+ val b = Output(Bool())
+ }
+
+ val inputVec = IO(Vec(1, Input(new MyBundle)))
+ inputVec <> DontCare
+ assert(DataMirror.directionOf(inputVec.head.a) == Direction.Input)
+ assert(DataMirror.directionOf(inputVec.head.b) == Direction.Input)
+
+ val vecInput = IO(Input(Vec(1, new MyBundle)))
+ vecInput <> DontCare
+ assert(DataMirror.directionOf(vecInput.head.a) == Direction.Input)
+ assert(DataMirror.directionOf(vecInput.head.b) == Direction.Input)
+
+ val vecInputFlipped = IO(Input(Vec(1, Flipped(new MyBundle))))
+ vecInputFlipped <> DontCare
+ assert(DataMirror.directionOf(vecInputFlipped.head.a) == Direction.Input)
+ assert(DataMirror.directionOf(vecInputFlipped.head.b) == Direction.Input)
+
+ val outputVec = IO(Vec(1, Output(new MyBundle)))
+ outputVec <> DontCare
+ assert(DataMirror.directionOf(outputVec.head.a) == Direction.Output)
+ assert(DataMirror.directionOf(outputVec.head.b) == Direction.Output)
+
+ val vecOutput = IO(Output(Vec(1, new MyBundle)))
+ vecOutput <> DontCare
+ assert(DataMirror.directionOf(vecOutput.head.a) == Direction.Output)
+ assert(DataMirror.directionOf(vecOutput.head.b) == Direction.Output)
+
+ val vecOutputFlipped = IO(Output(Vec(1, Flipped(new MyBundle))))
+ vecOutputFlipped <> DontCare
+ assert(DataMirror.directionOf(vecOutputFlipped.head.a) == Direction.Output)
+ assert(DataMirror.directionOf(vecOutputFlipped.head.b) == Direction.Output)
+ }
+
+ val elaborated = Driver.elaborate(() => new MyModule)
+
+ val emitted: String = Driver.emit(elaborated)
+ val firrtl: String = Driver.toFirrtl(elaborated).serialize
+
+ // Check that emitted directions are correct.
+ Seq(emitted, firrtl).foreach { o => {
+ // Chisel Emitter formats spacing a little differently than the
+ // FIRRTL Emitter :-(
+ val s = o.replace("{a", "{ a")
+ assert(s.contains("input inputVec : { a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("input vecInput : { a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("input vecInputFlipped : { a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("output outputVec : { a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("output vecOutput : { a : UInt<1>, b : UInt<1>}[1]"))
+ assert(s.contains("output vecOutputFlipped : { a : UInt<1>, b : UInt<1>}[1]"))
+ } }
+ }
}