Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIRRTL] FART: logic to reuse existing port can result in the wrong reset #7271

Open
youngar opened this issue Jul 2, 2024 · 0 comments
Open
Labels
bug Something isn't working FIRRTL Involving the `firrtl` dialect

Comments

@youngar
Copy link
Member

youngar commented Jul 2, 2024

Given this FIRRTL:

FIRRTL version 4.0.0
circuit Foo: %[[
  {"class":"sifive.enterprise.firrtl.FullAsyncResetAnnotation", "target":"~Foo|Foo>r"}
]]
  public module Foo:
    input p : UInt<1>
    input r : AsyncReset
    input c : Clock
    inst bar of Bar
    connect bar.r, asAsyncReset(UInt<1>(0))
    connect bar.c, c

  module Bar:
    input c : Clock
    input r : AsyncReset

    reg reg : UInt<8>, c

When compiled with firtool with no additional options, we see InferResets uses the port Bar.r as the reset domain for the internals of Bar.

firrtl.circuit "Foo" {
 firrtl.module @Foo(in %p: !firrtl.uint<1>, in %r: !firrtl.asyncreset [{class = "sifive.enterprise.firrt
l.FullAsyncResetAnnotation"}], in %c: !firrtl.clock) attributes {convention = #firrtl<convention scalariz
ed>} {
   %bar_c, %bar_r = firrtl.instance bar @Bar(in c: !firrtl.clock, in r: !firrtl.asyncreset)
   %c0_ui1 = firrtl.constant 0 : !firrtl.const.uint<1>
   %0 = firrtl.asAsyncReset %c0_ui1 : (!firrtl.const.uint<1>) -> !firrtl.const.asyncreset
   %1 = firrtl.constCast %0 : (!firrtl.const.asyncreset) -> !firrtl.asyncreset
   firrtl.matchingconnect %bar_r, %1 : !firrtl.asyncreset
   firrtl.matchingconnect %bar_c, %c : !firrtl.clock
 }
 firrtl.module private @Bar(in %c: !firrtl.clock, in %r: !firrtl.asyncreset) {
   %reg = firrtl.reg %c : !firrtl.clock, !firrtl.uint<8>
 }
}

// -----// IR Dump After InferResets (firrtl-infer-resets) //----- //
firrtl.circuit "Foo" {
 firrtl.module @Foo(in %p: !firrtl.uint<1>, in %r: !firrtl.asyncreset [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}], in %c: !firrtl.clock) attributes {convention = #firrtl<convention scalarized>} {
   %bar_c, %bar_r = firrtl.instance bar @Bar(in c: !firrtl.clock, in r: !firrtl.asyncreset)
   firrtl.matchingconnect %bar_r, %r : !firrtl.asyncreset
   %c0_ui1 = firrtl.constant 0 : !firrtl.const.uint<1>
   %0 = firrtl.asAsyncReset %c0_ui1 : (!firrtl.const.uint<1>) -> !firrtl.const.asyncreset
   %1 = firrtl.constCast %0 : (!firrtl.const.asyncreset) -> !firrtl.asyncreset
   firrtl.matchingconnect %bar_r, %1 : !firrtl.asyncreset
   firrtl.matchingconnect %bar_c, %c : !firrtl.clock
 }
 firrtl.module private @Bar(in %c: !firrtl.clock, in %r: !firrtl.asyncreset) {
   %c0_ui8 = firrtl.constant 0 : !firrtl.const.uint<8>
   %reg = firrtl.regreset %c, %r, %c0_ui8 : !firrtl.clock, !firrtl.asyncreset, !firrtl.const.uint<8>, !firrtl.uint<8>
 }
}

I would expect a new port to be added to Bar and it to be connected to Foo.r. This mistake happens because the logic in InferResetsPass::determineImpl tries to reuse existing reset ports in submodules, which it does by matching on the type and port name, which is not nearly enough. If we change the name of the port Bar.r to something other than r, then it will not reuse the port and will drive the correct reset signal to its target.

@youngar youngar added bug Something isn't working FIRRTL Involving the `firrtl` dialect labels Jul 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working FIRRTL Involving the `firrtl` dialect
Projects
None yet
Development

No branches or pull requests

1 participant