question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TopWiringTransform must run before LowerTypes

See original GitHub issue

Checklist

  • Did you specify the current behavior?
  • Did you specify the expected behavior?
  • Did you provide a code example showing the problem?
  • Did you describe your environment?
  • Did you specify relevant external information?

What is the current behavior?

If you try to top wire a bundle with flipped connections the TopWiringTransform runs before LowerTypes, then you expectedly get a bundle at the top with flipped connections. If the TopWiringTransform runs after LowerTypes, flippedness is lost and all top wired ports will be outputs.

With the current dependencies for TopWiringTransform, running after LowerTypes is a legal ordering.

What is the expected behavior?

The destruction of flippedness isn’t what the user (me) wants here. TopWiring should run before LowerTypes.

Steps to Reproduce

If you add a dummy transform to push TopWiring later, you can change the direction of a top-wired port from ir.Input to ir.Output.

package firrtlTests.transforms

import firrtl.{
  ir,
  CircuitState,
  DependencyAPIMigration,
  Parser,
  Transform
}
import firrtl.annotations.{
  CircuitName,
  ComponentName,
  ModuleName
}
import firrtl.options.Dependency
import firrtl.passes.LowerTypes
import firrtl.testutils.FirrtlCheckers._
import firrtl.transforms.TopWiring.{
  TopWiringAnnotation,
  TopWiringTransform
}

import org.scalatest.flatspec.AnyFlatSpec

object Dummy extends Transform with DependencyAPIMigration {
  override def prerequisites = Seq(Dependency(LowerTypes))
  override def optionalPrerequisites = Nil
  override def optionalPrerequisiteOf = Seq(Dependency[TopWiringTransform])
  override def invalidates(a: Transform) = false
  override def execute(a: CircuitState) = a
}

class TopWiringBug extends AnyFlatSpec {

  "TopWiringTransform" should "preserver directionality after LowerTypes?" in {
    val input =
      """|circuit Foo:
         |  module Foo:
         |    wire a: {flip b: UInt<1>}
         |    a is invalid
         |""".stripMargin
    val annos = Seq(
      TopWiringAnnotation(ComponentName(s"a", ModuleName(s"Foo", CircuitName(s"Foo"))), s"t_"),
    )

    val compiler = new firrtl.stage.transforms.Compiler(
      Seq(
        Dependency[TopWiringTransform],
        Dependency(LowerTypes),
        Dependency(Dummy) /* Including Dummy causes this test to fail */
      )
    )

    compiler.transform(CircuitState(Parser.parse(input), annos)) should containTree {
      case ir.Port(_, "t_a_b", ir.Input, _) => true
    }
  }

}

Your environment

Current-ish master: 05ba1c9d52c056e33b4121ea55812ae596016ea3

External Information

None.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
davidbiancolincommented, Jul 11, 2020

Is #1750 back-portable?

#1750 is backportable to 1.3.x and seems to make sense to do so as it fixes the ordering bug (or defines a scheduling-independent behavior).

Indeed.

Hmm… if FireSim is invoking TopWiringTransform directly and not relying on FIRRTL to schedule it, then maybe #1750 wouldn’t make a difference one way or another. It sounds like FireSim isn’t using either -fct TopWiringTransform or a RunFirrtlTransformAnnotation for scheduling. Is that right?

There’s one case where we’re dynamically adding a transform that invokes TopWiringTransform (using our own mechanism, not the two you gave) – so long as that transform defines the right prerequisites there will be no surprises. All of the other instances of this are part of the core compiler and are statically scheduled in a mega SeqTransform like thing – those should will likely be fine.

Regardless, if you need something immediate to use, the following will force the scheduling behavior one way or another:

/** Modified TopWiringTransform that ignores flips when top-wiring */
class TopWiringDirectionless extends TopWiringTransform {
  override def prerequisites = Dependency(LowerTypes) +: super.prerequisites
}

/** Modified TopWiringTransform that preserves flips when top-wiring. */
TopWiringPreserveDirections extends Transform with DependencyAPIMigration {

    private val underlying = new TopWiringTransform

    override def prerequisites = underlying.prerequisites
    override def optionalPrerequisites = underlying.prerequisites
    override def optionalPrerequisiteOf = Dependency(LowerTypes) +: underlying.optionalPrerequisiteOf
    override def invalidates(a: Transform) = underlying.invalidates(a)

    override def execute(a: CircuitState) = underlying.execute(a)

}

Note: the type of optionalPrerequisiteOf, normally Seq[Dependency[Transform]], was accidentally specialized to Seq[Dependency[Emitter]] and this is preventing overriding.

Thanks for the tips!

0reactions
seldridgecommented, Jul 11, 2020

It’s to expose a port of a submodule and drive it from the outside. Roughly:

val foo = Module(new Foo { val bar = IO(new Bar) } )
val baz = Wire(chiselTypeOf(foo.bar))
baz := foo.bar
topWire(baz)

TopWiringTransform was convenient because it could be done from the point where the module was instantiated as opposed to having to know the type of the module port and do sources/sinks for the WiringTransform.

This worked at some point, then after accumulating some custom transforms, I noticed that directions started getting stripped.

Read more comments on GitHub >

github_iconTop Results From Across the Web

DependencyAPI - firrtl 1.5.3 - javadoc.io
A prerequisite is a transform that must run before this transform. An optional prerequisites is transform that should run before this transform if...
Read more >
firrtl 1.4.4 - firrtl.Transform
All transform that must run before this transform. All transform that must run before this transform. Definition Classes: Transform → DependencyAPI; Note.
Read more >
java.io.FileWriter Scala Example - ProgramCreek.com
This page shows Scala examples of java.io.FileWriter.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found