diff options
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/RawModule.scala | 19 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/Direction.scala | 106 |
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]")) + } } + } } |
