circt/test/Dialect/FIRRTL/infer-resets.mlir

1246 lines
65 KiB
MLIR

// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-resets))' --verify-diagnostics --split-input-file %s | FileCheck %s
// Tests extracted from:
// - github.com/chipsalliance/firrtl:
// - test/scala/firrtlTests/InferResetsSpec.scala
// - github.com/sifive/$internal:
// - test/scala/firrtl/FullAsyncResetTransform.scala
firrtl.circuit "Foo" {
firrtl.module @Foo() {}
//===----------------------------------------------------------------------===//
// Reset Inference
//===----------------------------------------------------------------------===//
// Provoke two existing reset networks being merged.
// CHECK-LABEL: firrtl.module @MergeNetsChild1
// CHECK-SAME: in %reset: !firrtl.asyncreset
firrtl.module @MergeNetsChild1(in %reset: !firrtl.reset) {
// CHECK: %localReset = firrtl.wire : !firrtl.asyncreset
%localReset = firrtl.wire : !firrtl.reset
firrtl.matchingconnect %localReset, %reset : !firrtl.reset
}
// CHECK-LABEL: firrtl.module @MergeNetsChild2
// CHECK-SAME: in %reset: !firrtl.asyncreset
firrtl.module @MergeNetsChild2(in %reset: !firrtl.reset) {
// CHECK: %localReset = firrtl.wire : !firrtl.asyncreset
%localReset = firrtl.wire : !firrtl.reset
firrtl.matchingconnect %localReset, %reset : !firrtl.reset
}
// CHECK-LABEL: firrtl.module @MergeNetsTop
firrtl.module @MergeNetsTop(in %reset: !firrtl.asyncreset) {
// CHECK: %localReset = firrtl.wire : !firrtl.asyncreset
%localReset = firrtl.wire : !firrtl.reset
%t = firrtl.resetCast %reset : (!firrtl.asyncreset) -> !firrtl.reset
firrtl.matchingconnect %localReset, %t : !firrtl.reset
// CHECK: %c1_reset = firrtl.instance c1 @MergeNetsChild1(in reset: !firrtl.asyncreset)
// CHECK: %c2_reset = firrtl.instance c2 @MergeNetsChild2(in reset: !firrtl.asyncreset)
%c1_reset = firrtl.instance c1 @MergeNetsChild1(in reset: !firrtl.reset)
%c2_reset = firrtl.instance c2 @MergeNetsChild2(in reset: !firrtl.reset)
firrtl.matchingconnect %c1_reset, %localReset : !firrtl.reset
firrtl.matchingconnect %c2_reset, %localReset : !firrtl.reset
}
// Should support casting to other types
// CHECK-LABEL: firrtl.module @CastingToOtherTypes
firrtl.module @CastingToOtherTypes(in %a: !firrtl.uint<1>, out %v: !firrtl.uint<1>, out %w: !firrtl.sint<1>, out %x: !firrtl.clock, out %y: !firrtl.asyncreset) {
// CHECK: %r = firrtl.wire : !firrtl.uint<1>
%r = firrtl.wire : !firrtl.reset
%0 = firrtl.asUInt %r : (!firrtl.reset) -> !firrtl.uint<1>
%1 = firrtl.asSInt %r : (!firrtl.reset) -> !firrtl.sint<1>
%2 = firrtl.asClock %r : (!firrtl.reset) -> !firrtl.clock
%3 = firrtl.asAsyncReset %r : (!firrtl.reset) -> !firrtl.asyncreset
%4 = firrtl.resetCast %a : (!firrtl.uint<1>) -> !firrtl.reset
firrtl.matchingconnect %r, %4 : !firrtl.reset
firrtl.matchingconnect %v, %0 : !firrtl.uint<1>
firrtl.matchingconnect %w, %1 : !firrtl.sint<1>
firrtl.matchingconnect %x, %2 : !firrtl.clock
firrtl.matchingconnect %y, %3 : !firrtl.asyncreset
}
// Should support const-casts
// CHECK-LABEL: firrtl.module @ConstCast
firrtl.module @ConstCast(in %a: !firrtl.const.uint<1>) {
// CHECK: %r = firrtl.wire : !firrtl.uint<1>
%r = firrtl.wire : !firrtl.reset
%0 = firrtl.resetCast %a : (!firrtl.const.uint<1>) -> !firrtl.const.reset
%1 = firrtl.constCast %0 : (!firrtl.const.reset) -> !firrtl.reset
firrtl.matchingconnect %r, %1 : !firrtl.reset
}
// Should work across Module boundaries
// CHECK-LABEL: firrtl.module @ModuleBoundariesChild
// CHECK-SAME: in %childReset: !firrtl.uint<1>
firrtl.module @ModuleBoundariesChild(in %clock: !firrtl.clock, in %childReset: !firrtl.reset, in %x: !firrtl.uint<8>, out %z: !firrtl.uint<8>) {
%c123_ui = firrtl.constant 123 : !firrtl.uint
// CHECK: %r = firrtl.regreset %clock, %childReset, %c123_ui : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint, !firrtl.uint<8>
%r = firrtl.regreset %clock, %childReset, %c123_ui : !firrtl.clock, !firrtl.reset, !firrtl.uint, !firrtl.uint<8>
firrtl.matchingconnect %r, %x : !firrtl.uint<8>
firrtl.matchingconnect %z, %r : !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @ModuleBoundariesTop
firrtl.module @ModuleBoundariesTop(in %clock: !firrtl.clock, in %reset: !firrtl.uint<1>, in %x: !firrtl.uint<8>, out %z: !firrtl.uint<8>) {
// CHECK: {{.*}} = firrtl.instance c @ModuleBoundariesChild(in clock: !firrtl.clock, in childReset: !firrtl.uint<1>, in x: !firrtl.uint<8>, out z: !firrtl.uint<8>)
%c_clock, %c_childReset, %c_x, %c_z = firrtl.instance c @ModuleBoundariesChild(in clock: !firrtl.clock, in childReset: !firrtl.reset, in x: !firrtl.uint<8>, out z: !firrtl.uint<8>)
firrtl.matchingconnect %c_clock, %clock : !firrtl.clock
firrtl.connect %c_childReset, %reset : !firrtl.reset, !firrtl.uint<1>
firrtl.matchingconnect %c_x, %x : !firrtl.uint<8>
firrtl.matchingconnect %z, %c_z : !firrtl.uint<8>
}
// Should work across multiple Module boundaries
// CHECK-LABEL: firrtl.module @MultipleModuleBoundariesChild
// CHECK-SAME: in %resetIn: !firrtl.uint<1>
// CHECK-SAME: out %resetOut: !firrtl.uint<1>
firrtl.module @MultipleModuleBoundariesChild(in %resetIn: !firrtl.reset, out %resetOut: !firrtl.reset) {
firrtl.matchingconnect %resetOut, %resetIn : !firrtl.reset
}
// CHECK-LABEL: firrtl.module @MultipleModuleBoundariesTop
firrtl.module @MultipleModuleBoundariesTop(in %clock: !firrtl.clock, in %reset: !firrtl.uint<1>, in %x: !firrtl.uint<8>, out %z: !firrtl.uint<8>) {
// CHECK: {{.*}} = firrtl.instance c @MultipleModuleBoundariesChild(in resetIn: !firrtl.uint<1>, out resetOut: !firrtl.uint<1>)
%c_resetIn, %c_resetOut = firrtl.instance c @MultipleModuleBoundariesChild(in resetIn: !firrtl.reset, out resetOut: !firrtl.reset)
firrtl.connect %c_resetIn, %reset : !firrtl.reset, !firrtl.uint<1>
%c123_ui = firrtl.constant 123 : !firrtl.uint
// CHECK: %r = firrtl.regreset %clock, %c_resetOut, %c123_ui : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint, !firrtl.uint<8>
%r = firrtl.regreset %clock, %c_resetOut, %c123_ui : !firrtl.clock, !firrtl.reset, !firrtl.uint, !firrtl.uint<8>
firrtl.matchingconnect %r, %x : !firrtl.uint<8>
firrtl.matchingconnect %z, %r : !firrtl.uint<8>
}
// Should work in nested and flipped aggregates with connect
// CHECK-LABEL: firrtl.module @NestedAggregates
// CHECK-SAME: out %buzz: !firrtl.bundle<foo flip: vector<bundle<a: asyncreset, b flip: asyncreset, c: uint<1>>, 2>, bar: vector<bundle<a: asyncreset, b flip: asyncreset, c: uint<8>>, 2>>
firrtl.module @NestedAggregates(out %buzz: !firrtl.bundle<foo flip: vector<bundle<a: asyncreset, b flip: reset, c: uint<1>>, 2>, bar: vector<bundle<a: reset, b flip: asyncreset, c: uint<8>>, 2>>) {
%0 = firrtl.subfield %buzz[bar] : !firrtl.bundle<foo flip: vector<bundle<a: asyncreset, b flip: reset, c: uint<1>>, 2>, bar: vector<bundle<a: reset, b flip: asyncreset, c: uint<8>>, 2>>
%1 = firrtl.subfield %buzz[foo] : !firrtl.bundle<foo flip: vector<bundle<a: asyncreset, b flip: reset, c: uint<1>>, 2>, bar: vector<bundle<a: reset, b flip: asyncreset, c: uint<8>>, 2>>
firrtl.connect %0, %1 : !firrtl.vector<bundle<a: reset, b flip: asyncreset, c: uint<8>>, 2>, !firrtl.vector<bundle<a: asyncreset, b flip: reset, c: uint<1>>, 2>
}
// Should work with deeply nested aggregates.
// CHECK-LABEL: firrtl.module @DeeplyNestedAggregates(in %reset: !firrtl.uint<1>, out %buzz: !firrtl.bundle<a: bundle<b: uint<1>>>) {
firrtl.module @DeeplyNestedAggregates(in %reset: !firrtl.uint<1>, out %buzz: !firrtl.bundle<a: bundle<b: reset>>) {
%0 = firrtl.subfield %buzz[a] : !firrtl.bundle<a: bundle<b : reset>>
%1 = firrtl.subfield %0[b] : !firrtl.bundle<b: reset>
// CHECK: firrtl.connect %1, %reset : !firrtl.uint<1>
firrtl.connect %1, %reset : !firrtl.reset, !firrtl.uint<1>
}
// Should not crash if a ResetType has no drivers
// CHECK-LABEL: firrtl.module @DontCrashIfNoDrivers
// CHECK-SAME: out %out: !firrtl.uint<1>
firrtl.module @DontCrashIfNoDrivers(out %out: !firrtl.reset) {
%c1_ui = firrtl.constant 1 : !firrtl.uint
%c1_ui1 = firrtl.constant 1 : !firrtl.uint<1>
// CHECK: %w = firrtl.wire : !firrtl.uint<1>
%w = firrtl.wire : !firrtl.reset
firrtl.matchingconnect %out, %w : !firrtl.reset
// TODO: Enable the following once #1303 is fixed.
// firrtl.connect %out, %c1_ui : !firrtl.reset, !firrtl.uint
firrtl.connect %out, %c1_ui1 : !firrtl.reset, !firrtl.uint<1>
}
// Should allow concrete reset types to overrule invalidation
// CHECK-LABEL: firrtl.module @ConcreteResetOverruleInvalid
// CHECK-SAME: out %out: !firrtl.asyncreset
firrtl.module @ConcreteResetOverruleInvalid(in %in: !firrtl.asyncreset, out %out: !firrtl.reset) {
// CHECK: %invalid_asyncreset = firrtl.invalidvalue : !firrtl.asyncreset
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.matchingconnect %out, %invalid_reset : !firrtl.reset
firrtl.connect %out, %in : !firrtl.reset, !firrtl.asyncreset
}
// Should default to BoolType for Resets that are only invalidated
// CHECK-LABEL: firrtl.module @DefaultToBool
// CHECK-SAME: out %out: !firrtl.uint<1>
firrtl.module @DefaultToBool(out %out: !firrtl.reset) {
// CHECK: %invalid_ui1 = firrtl.invalidvalue : !firrtl.uint<1>
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.matchingconnect %out, %invalid_reset : !firrtl.reset
}
// Should not error if component of ResetType is invalidated and connected to an AsyncResetType
// CHECK-LABEL: firrtl.module @OverrideInvalidWithDifferentResetType
// CHECK-SAME: out %out: !firrtl.asyncreset
firrtl.module @OverrideInvalidWithDifferentResetType(in %cond: !firrtl.uint<1>, in %in: !firrtl.asyncreset, out %out: !firrtl.reset) {
// CHECK: %invalid_asyncreset = firrtl.invalidvalue : !firrtl.asyncreset
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.matchingconnect %out, %invalid_reset : !firrtl.reset
firrtl.when %cond : !firrtl.uint<1> {
firrtl.connect %out, %in : !firrtl.reset, !firrtl.asyncreset
}
}
// Should allow ResetType to drive AsyncResets or UInt<1>
// CHECK-LABEL: firrtl.module @ResetDrivesAsyncResetOrBool1
firrtl.module @ResetDrivesAsyncResetOrBool1(in %in: !firrtl.uint<1>, out %out: !firrtl.uint<1>) {
// CHECK: %w = firrtl.wire : !firrtl.uint<1>
%w = firrtl.wire : !firrtl.reset
firrtl.connect %w, %in : !firrtl.reset, !firrtl.uint<1>
firrtl.connect %out, %w : !firrtl.uint<1>, !firrtl.reset
}
// CHECK-LABEL: firrtl.module @ResetDrivesAsyncResetOrBool2
firrtl.module @ResetDrivesAsyncResetOrBool2(out %foo: !firrtl.bundle<a flip: uint<1>>, in %bar: !firrtl.bundle<a flip: uint<1>>) {
// CHECK: %w = firrtl.wire : !firrtl.bundle<a flip: uint<1>>
%w = firrtl.wire : !firrtl.bundle<a flip: reset>
firrtl.connect %foo, %w : !firrtl.bundle<a flip: uint<1>>, !firrtl.bundle<a flip: reset>
firrtl.connect %w, %bar : !firrtl.bundle<a flip: reset>, !firrtl.bundle<a flip: uint<1>>
}
// CHECK-LABEL: firrtl.module @ResetDrivesAsyncResetOrBool3
firrtl.module @ResetDrivesAsyncResetOrBool3(in %in: !firrtl.uint<1>, out %out: !firrtl.uint<1>) {
// CHECK: %w = firrtl.wire : !firrtl.uint<1>
%w = firrtl.wire : !firrtl.reset
firrtl.connect %w, %in : !firrtl.reset, !firrtl.uint<1>
firrtl.connect %out, %w : !firrtl.uint<1>, !firrtl.reset
}
// Should support inferring modules that would dedup differently
// CHECK-LABEL: firrtl.module @DedupDifferentlyChild1
// CHECK-SAME: in %childReset: !firrtl.uint<1>
firrtl.module @DedupDifferentlyChild1(in %clock: !firrtl.clock, in %childReset: !firrtl.reset, in %x: !firrtl.uint<8>, out %z: !firrtl.uint<8>) {
%c123_ui = firrtl.constant 123 : !firrtl.uint
// CHECK: %r = firrtl.regreset %clock, %childReset, %c123_ui : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint, !firrtl.uint<8>
%r = firrtl.regreset %clock, %childReset, %c123_ui : !firrtl.clock, !firrtl.reset, !firrtl.uint, !firrtl.uint<8>
firrtl.matchingconnect %r, %x : !firrtl.uint<8>
firrtl.matchingconnect %z, %r : !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @DedupDifferentlyChild2
// CHECK-SAME: in %childReset: !firrtl.asyncreset
firrtl.module @DedupDifferentlyChild2(in %clock: !firrtl.clock, in %childReset: !firrtl.reset, in %x: !firrtl.uint<8>, out %z: !firrtl.uint<8>) {
%c123_ui = firrtl.constant 123 : !firrtl.uint
// CHECK: %r = firrtl.regreset %clock, %childReset, %c123_ui : !firrtl.clock, !firrtl.asyncreset, !firrtl.uint, !firrtl.uint<8>
%r = firrtl.regreset %clock, %childReset, %c123_ui : !firrtl.clock, !firrtl.reset, !firrtl.uint, !firrtl.uint<8>
firrtl.matchingconnect %r, %x : !firrtl.uint<8>
firrtl.matchingconnect %z, %r : !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @DedupDifferentlyTop
firrtl.module @DedupDifferentlyTop(in %clock: !firrtl.clock, in %reset1: !firrtl.uint<1>, in %reset2: !firrtl.asyncreset, in %x: !firrtl.vector<uint<8>, 2>, out %z: !firrtl.vector<uint<8>, 2>) {
// CHECK: {{.*}} = firrtl.instance c1 @DedupDifferentlyChild1(in clock: !firrtl.clock, in childReset: !firrtl.uint<1>
%c1_clock, %c1_childReset, %c1_x, %c1_z = firrtl.instance c1 @DedupDifferentlyChild1(in clock: !firrtl.clock, in childReset: !firrtl.reset, in x: !firrtl.uint<8>, out z: !firrtl.uint<8>)
firrtl.matchingconnect %c1_clock, %clock : !firrtl.clock
firrtl.connect %c1_childReset, %reset1 : !firrtl.reset, !firrtl.uint<1>
%0 = firrtl.subindex %x[0] : !firrtl.vector<uint<8>, 2>
firrtl.matchingconnect %c1_x, %0 : !firrtl.uint<8>
%1 = firrtl.subindex %z[0] : !firrtl.vector<uint<8>, 2>
firrtl.matchingconnect %1, %c1_z : !firrtl.uint<8>
// CHECK: {{.*}} = firrtl.instance c2 @DedupDifferentlyChild2(in clock: !firrtl.clock, in childReset: !firrtl.asyncreset
%c2_clock, %c2_childReset, %c2_x, %c2_z = firrtl.instance c2 @DedupDifferentlyChild2(in clock: !firrtl.clock, in childReset: !firrtl.reset, in x: !firrtl.uint<8>, out z: !firrtl.uint<8>)
firrtl.matchingconnect %c2_clock, %clock : !firrtl.clock
firrtl.connect %c2_childReset, %reset2 : !firrtl.reset, !firrtl.asyncreset
%2 = firrtl.subindex %x[1] : !firrtl.vector<uint<8>, 2>
firrtl.matchingconnect %c2_x, %2 : !firrtl.uint<8>
%3 = firrtl.subindex %z[1] : !firrtl.vector<uint<8>, 2>
firrtl.matchingconnect %3, %c2_z : !firrtl.uint<8>
}
// Should infer based on what a component *drives* not just what drives it
// CHECK-LABEL: firrtl.module @InferBasedOnDriven
// CHECK-SAME: out %out: !firrtl.asyncreset
firrtl.module @InferBasedOnDriven(in %in: !firrtl.asyncreset, out %out: !firrtl.reset) {
// CHECK: %w = firrtl.wire : !firrtl.asyncreset
// CHECK: %invalid_asyncreset = firrtl.invalidvalue : !firrtl.asyncreset
%w = firrtl.wire : !firrtl.reset
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.matchingconnect %w, %invalid_reset : !firrtl.reset
firrtl.matchingconnect %out, %w : !firrtl.reset
firrtl.connect %out, %in : !firrtl.reset, !firrtl.asyncreset
}
// Should infer from connections, ignoring the fact that the invalidation wins
// CHECK-LABEL: firrtl.module @InferIgnoreInvalidation
// CHECK-SAME: out %out: !firrtl.asyncreset
firrtl.module @InferIgnoreInvalidation(in %in: !firrtl.asyncreset, out %out: !firrtl.reset) {
// CHECK: %invalid_asyncreset = firrtl.invalidvalue : !firrtl.asyncreset
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.connect %out, %in : !firrtl.reset, !firrtl.asyncreset
firrtl.matchingconnect %out, %invalid_reset : !firrtl.reset
}
// Should not propagate type info from downstream across a cast
// CHECK-LABEL: firrtl.module @DontPropagateUpstreamAcrossCast
// CHECK-SAME: out %out0: !firrtl.asyncreset
// CHECK-SAME: out %out1: !firrtl.uint<1>
firrtl.module @DontPropagateUpstreamAcrossCast(in %in0: !firrtl.asyncreset, in %in1: !firrtl.uint<1>, out %out0: !firrtl.reset, out %out1: !firrtl.reset) {
// CHECK: %w = firrtl.wire : !firrtl.uint<1>
%w = firrtl.wire : !firrtl.reset
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.matchingconnect %w, %invalid_reset : !firrtl.reset
%0 = firrtl.asAsyncReset %w : (!firrtl.reset) -> !firrtl.asyncreset
firrtl.connect %out0, %0 : !firrtl.reset, !firrtl.asyncreset
firrtl.matchingconnect %out1, %w : !firrtl.reset
firrtl.connect %out0, %in0 : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %out1, %in1 : !firrtl.reset, !firrtl.uint<1>
}
// Should take into account both internal and external constraints on Module port types
// CHECK-LABEL: firrtl.module @InternalAndExternalChild
// CHECK-SAME: out %o: !firrtl.asyncreset
firrtl.module @InternalAndExternalChild(in %i: !firrtl.asyncreset, out %o: !firrtl.reset) {
firrtl.connect %o, %i : !firrtl.reset, !firrtl.asyncreset
}
// CHECK-LABEL: firrtl.module @InternalAndExternalTop
firrtl.module @InternalAndExternalTop(in %in: !firrtl.asyncreset, out %out: !firrtl.asyncreset) {
// CHECK: {{.*}} = firrtl.instance c @InternalAndExternalChild(in i: !firrtl.asyncreset, out o: !firrtl.asyncreset)
%c_i, %c_o = firrtl.instance c @InternalAndExternalChild(in i: !firrtl.asyncreset, out o: !firrtl.reset)
firrtl.matchingconnect %c_i, %in : !firrtl.asyncreset
firrtl.connect %out, %c_o : !firrtl.asyncreset, !firrtl.reset
}
// Should not crash on combinational loops
// CHECK-LABEL: firrtl.module @NoCrashOnCombLoop
// CHECK-SAME: out %out: !firrtl.asyncreset
firrtl.module @NoCrashOnCombLoop(in %in: !firrtl.asyncreset, out %out: !firrtl.reset) {
%w0 = firrtl.wire : !firrtl.reset
%w1 = firrtl.wire : !firrtl.reset
firrtl.connect %w0, %in : !firrtl.reset, !firrtl.asyncreset
firrtl.matchingconnect %w0, %w1 : !firrtl.reset
firrtl.matchingconnect %w1, %w0 : !firrtl.reset
firrtl.connect %out, %in : !firrtl.reset, !firrtl.asyncreset
}
// Should not treat a single `invalidvalue` connected to different resets as a
// connection of the resets themselves.
// CHECK-LABEL: firrtl.module @InvalidValueShouldNotConnect
// CHECK-SAME: out %r0: !firrtl.asyncreset
// CHECK-SAME: out %r1: !firrtl.asyncreset
// CHECK-SAME: out %r2: !firrtl.uint<1>
// CHECK-SAME: out %r3: !firrtl.uint<1>
firrtl.module @InvalidValueShouldNotConnect(
in %ar: !firrtl.asyncreset,
in %sr: !firrtl.uint<1>,
out %r0: !firrtl.reset,
out %r1: !firrtl.reset,
out %r2: !firrtl.reset,
out %r3: !firrtl.reset
) {
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
firrtl.matchingconnect %r0, %invalid_reset : !firrtl.reset
firrtl.matchingconnect %r1, %invalid_reset : !firrtl.reset
firrtl.matchingconnect %r2, %invalid_reset : !firrtl.reset
firrtl.matchingconnect %r3, %invalid_reset : !firrtl.reset
firrtl.connect %r0, %ar : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r1, %ar : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r2, %sr : !firrtl.reset, !firrtl.uint<1>
firrtl.connect %r3, %sr : !firrtl.reset, !firrtl.uint<1>
}
// Should properly adjust the type of external modules.
// CHECK-LABEL: firrtl.extmodule @ShouldAdjustExtModule1
// CHECK-SAME: in reset: !firrtl.uint<1>
firrtl.extmodule @ShouldAdjustExtModule1(in reset: !firrtl.reset)
// CHECK-LABEL: firrtl.module @ShouldAdjustExtModule2
// CHECK: %x_reset = firrtl.instance x @ShouldAdjustExtModule1(in reset: !firrtl.uint<1>)
firrtl.module @ShouldAdjustExtModule2() {
%x_reset = firrtl.instance x @ShouldAdjustExtModule1(in reset: !firrtl.reset)
%c1_ui1 = firrtl.constant 1 : !firrtl.uint<1>
firrtl.connect %x_reset, %c1_ui1 : !firrtl.reset, !firrtl.uint<1>
}
// Should not crash if there are connects with foreign types.
// CHECK-LABEL: firrtl.module @ForeignTypes
firrtl.module @ForeignTypes(out %out: !firrtl.reset) {
%0 = firrtl.wire : index
%1 = firrtl.wire : index
firrtl.matchingconnect %0, %1 : index
// CHECK-NEXT: [[W0:%.+]] = firrtl.wire : index
// CHECK-NEXT: [[W1:%.+]] = firrtl.wire : index
// CHECK-NEXT: firrtl.matchingconnect [[W0]], [[W1]] : index
%c1_ui1 = firrtl.constant 1 : !firrtl.uint<1>
firrtl.connect %out, %c1_ui1 : !firrtl.reset, !firrtl.uint<1>
}
//===----------------------------------------------------------------------===//
// Full Async Reset
//===----------------------------------------------------------------------===//
// CHECK-LABEL: firrtl.module @ConsumeIgnoreAnno
// CHECK-NOT: ExcludeFromFullResetAnnotation
firrtl.module @ConsumeIgnoreAnno() attributes {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} {
}
} // firrtl.circuit
// -----
// AsyncReset-less registers should inherit the annotated async reset signal.
firrtl.circuit "Top" {
// CHECK-LABEL: firrtl.module @Top
firrtl.module @Top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %init: !firrtl.uint<1>, in %in: !firrtl.uint<8>, in %extraReset: !firrtl.asyncreset ) attributes {
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "async"}]]} {
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<8>
// CHECK: %reg1 = firrtl.regreset sym @reg1 %clock, %extraReset, %c0_ui8
%reg1 = firrtl.reg sym @reg1 %clock : !firrtl.clock, !firrtl.uint<8>
firrtl.matchingconnect %reg1, %in : !firrtl.uint<8>
// Existing async reset remains untouched.
// CHECK: %reg2 = firrtl.regreset %clock, %reset, %c1_ui8
%reg2 = firrtl.regreset %clock, %reset, %c1_ui8 : !firrtl.clock, !firrtl.asyncreset, !firrtl.uint<8>, !firrtl.uint<8>
firrtl.matchingconnect %reg2, %in : !firrtl.uint<8>
// Existing sync reset is moved to mux.
// CHECK: %reg3 = firrtl.regreset %clock, %extraReset, %c0_ui8
// CHECK: %0 = firrtl.mux(%init, %c1_ui8, %reg3)
// CHECK: %1 = firrtl.mux(%init, %c1_ui8, %in)
// CHECK: firrtl.matchingconnect %reg3, %1
%reg3 = firrtl.regreset %clock, %init, %c1_ui8 : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint<8>, !firrtl.uint<8>
firrtl.matchingconnect %reg3, %in : !firrtl.uint<8>
// Factoring of sync reset into mux works through subfield op.
// CHECK: %reg4 = firrtl.regreset %clock, %extraReset, %2
// CHECK: %4 = firrtl.mux(%init, %reset4, %reg4)
// CHECK: %5 = firrtl.subfield %reset4[a]
// CHECK: %6 = firrtl.subfield %reg4[a]
// CHECK: %7 = firrtl.mux(%init, %5, %in)
// CHECK: firrtl.matchingconnect %6, %7
%reset4 = firrtl.wire : !firrtl.bundle<a: uint<8>>
%reg4 = firrtl.regreset %clock, %init, %reset4 : !firrtl.clock, !firrtl.uint<1>, !firrtl.bundle<a: uint<8>>, !firrtl.bundle<a: uint<8>>
%0 = firrtl.subfield %reg4[a] : !firrtl.bundle<a: uint<8>>
firrtl.matchingconnect %0, %in : !firrtl.uint<8>
// Factoring of sync reset into mux works through subindex op.
// CHECK: %reg5 = firrtl.regreset %clock, %extraReset, %8
// CHECK: %10 = firrtl.mux(%init, %reset5, %reg5)
// CHECK: firrtl.matchingconnect %reg5, %10
// CHECK: %11 = firrtl.subindex %reset5[0]
// CHECK: %12 = firrtl.subindex %reg5[0]
// CHECK: %13 = firrtl.mux(%init, %11, %in)
// CHECK: firrtl.matchingconnect %12, %13
%reset5 = firrtl.wire : !firrtl.vector<uint<8>, 1>
%reg5 = firrtl.regreset %clock, %init, %reset5 : !firrtl.clock, !firrtl.uint<1>, !firrtl.vector<uint<8>, 1>, !firrtl.vector<uint<8>, 1>
%1 = firrtl.subindex %reg5[0] : !firrtl.vector<uint<8>, 1>
firrtl.matchingconnect %1, %in : !firrtl.uint<8>
// Factoring of sync reset into mux works through subaccess op.
// CHECK: %reg6 = firrtl.regreset %clock, %extraReset, %14
// CHECK: %16 = firrtl.mux(%init, %reset6, %reg6)
// CHECK: firrtl.matchingconnect %reg6, %16
// CHECK: %17 = firrtl.subaccess %reset6[%in]
// CHECK: %18 = firrtl.subaccess %reg6[%in]
// CHECK: %19 = firrtl.mux(%init, %17, %in)
// CHECK: firrtl.matchingconnect %18, %19
%reset6 = firrtl.wire : !firrtl.vector<uint<8>, 1>
%reg6 = firrtl.regreset %clock, %init, %reset6 : !firrtl.clock, !firrtl.uint<1>, !firrtl.vector<uint<8>, 1>, !firrtl.vector<uint<8>, 1>
%2 = firrtl.subaccess %reg6[%in] : !firrtl.vector<uint<8>, 1>, !firrtl.uint<8>
firrtl.matchingconnect %2, %in : !firrtl.uint<8>
// Subfields that are never assigned to should not leave unused reset
// subfields behind.
// CHECK-NOT: firrtl.subfield %reset4[a]
// CHECK: %20 = firrtl.subfield %reg4[a]
%3 = firrtl.subfield %reg4[a] : !firrtl.bundle<a: uint<8>>
}
}
// -----
// Reset-less registers should inherit the annotated sync reset signal.
firrtl.circuit "Top" {
// CHECK-LABEL: firrtl.module @Top
firrtl.module @Top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %init: !firrtl.uint<1>, in %in: !firrtl.uint<8>, in %extraReset: !firrtl.uint<1> ) attributes {
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "sync"}]]} {
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<8>
// CHECK: %reg1 = firrtl.regreset sym @reg1 %clock, %extraReset, %c0_ui8
%reg1 = firrtl.reg sym @reg1 %clock : !firrtl.clock, !firrtl.uint<8>
firrtl.matchingconnect %reg1, %in : !firrtl.uint<8>
// Existing async reset remains untouched.
// CHECK: %reg2 = firrtl.regreset %clock, %reset, %c1_ui8
%reg2 = firrtl.regreset %clock, %reset, %c1_ui8 : !firrtl.clock, !firrtl.asyncreset, !firrtl.uint<8>, !firrtl.uint<8>
firrtl.matchingconnect %reg2, %in : !firrtl.uint<8>
// Existing sync reset remains untouched.
// CHECK: %reg3 = firrtl.regreset %clock, %init, %c1_ui8
%reg3 = firrtl.regreset %clock, %init, %c1_ui8 : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint<8>, !firrtl.uint<8>
firrtl.matchingconnect %reg3, %in : !firrtl.uint<8>
}
}
// -----
// Async reset inference should be able to construct reset values for aggregate
// types.
firrtl.circuit "Top" {
// CHECK-LABEL: firrtl.module @Top
firrtl.module @Top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
// CHECK: %c0_ui = firrtl.constant 0 : !firrtl.const.uint
// CHECK: %reg_uint = firrtl.regreset %clock, %reset, %c0_ui
%reg_uint = firrtl.reg %clock : !firrtl.clock, !firrtl.uint
// CHECK: %c0_si = firrtl.constant 0 : !firrtl.const.sint
// CHECK: %reg_sint = firrtl.regreset %clock, %reset, %c0_si
%reg_sint = firrtl.reg %clock : !firrtl.clock, !firrtl.sint
// CHECK: %0 = firrtl.wire : !firrtl.const.bundle<a: uint<8>, b: bundle<x: uint<8>, y: uint<8>>>
// CHECK: %c0_ui8 = firrtl.constant 0 : !firrtl.const.uint<8>
// CHECK: %1 = firrtl.subfield %0[a]
// CHECK: firrtl.matchingconnect %1, %c0_ui8
// CHECK: %2 = firrtl.wire : !firrtl.const.bundle<x: uint<8>, y: uint<8>>
// CHECK: %3 = firrtl.subfield %2[x]
// CHECK: firrtl.matchingconnect %3, %c0_ui8
// CHECK: %4 = firrtl.subfield %2[y]
// CHECK: firrtl.matchingconnect %4, %c0_ui8
// CHECK: %5 = firrtl.subfield %0[b]
// CHECK: firrtl.matchingconnect %5, %2
// CHECK: %reg_bundle = firrtl.regreset %clock, %reset, %0
%reg_bundle = firrtl.reg %clock : !firrtl.clock, !firrtl.bundle<a: uint<8>, b: bundle<x: uint<8>, y: uint<8>>>
// CHECK: %6 = firrtl.wire : !firrtl.const.vector<uint<8>, 4>
// CHECK: %c0_ui8_0 = firrtl.constant 0 : !firrtl.const.uint<8>
// CHECK: %7 = firrtl.subindex %6[0]
// CHECK: firrtl.matchingconnect %7, %c0_ui8_0
// CHECK: %8 = firrtl.subindex %6[1]
// CHECK: firrtl.matchingconnect %8, %c0_ui8_0
// CHECK: %9 = firrtl.subindex %6[2]
// CHECK: firrtl.matchingconnect %9, %c0_ui8_0
// CHECK: %10 = firrtl.subindex %6[3]
// CHECK: firrtl.matchingconnect %10, %c0_ui8_0
// CHECK: %reg_vector = firrtl.regreset %clock, %reset, %6
%reg_vector = firrtl.reg %clock : !firrtl.clock, !firrtl.vector<uint<8>, 4>
}
}
// -----
// Reset should reuse ports if name and type matches for async wiring.
firrtl.circuit "ReusePortsAsync" {
// CHECK-LABEL: firrtl.module @Child
// CHECK-SAME: in %clock: !firrtl.clock
// CHECK-SAME: in %reset: !firrtl.asyncreset
// CHECK: %reg = firrtl.regreset %clock, %reset, %c0_ui8
firrtl.module @Child(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @BadName
// CHECK-SAME: in %reset: !firrtl.asyncreset,
// CHECK-SAME: in %clock: !firrtl.clock
// CHECK-SAME: in %existingReset: !firrtl.asyncreset
// CHECK: %reg = firrtl.regreset %clock, %reset, %c0_ui8
firrtl.module @BadName(in %clock: !firrtl.clock, in %existingReset: !firrtl.asyncreset) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @BadType
// CHECK-SAME: in %reset_0: !firrtl.asyncreset,
// CHECK-SAME: in %clock: !firrtl.clock
// CHECK-SAME: in %reset: !firrtl.uint<1>
// CHECK: %reg = firrtl.regreset %clock, %reset_0, %c0_ui8
firrtl.module @BadType(in %clock: !firrtl.clock, in %reset: !firrtl.uint<1>) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @ReusePorts
firrtl.module @ReusePortsAsync(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
// CHECK: %child_clock, %child_reset = firrtl.instance child
// CHECK: firrtl.matchingconnect %child_reset, %reset
// CHECK: %badName_reset, %badName_clock, %badName_existingReset = firrtl.instance badName
// CHECK: firrtl.matchingconnect %badName_reset, %reset
// CHECK: %badType_reset_0, %badType_clock, %badType_reset = firrtl.instance badType
// CHECK: firrtl.matchingconnect %badType_reset_0, %reset
%child_clock, %child_reset = firrtl.instance child @Child(in clock: !firrtl.clock, in reset: !firrtl.asyncreset)
%badName_clock, %badName_existingReset = firrtl.instance badName @BadName(in clock: !firrtl.clock, in existingReset: !firrtl.asyncreset)
%badType_clock, %badType_reset = firrtl.instance badType @BadType(in clock: !firrtl.clock, in reset: !firrtl.uint<1>)
}
}
// -----
// Reset should reuse ports if name and type matches for sync wiring.
firrtl.circuit "ReusePortsSync" {
// CHECK-LABEL: firrtl.module @Child
// CHECK-SAME: in %clock: !firrtl.clock
// CHECK-SAME: in %reset: !firrtl.uint<1>
// CHECK: %reg = firrtl.regreset %clock, %reset, %c0_ui8
firrtl.module @Child(in %clock: !firrtl.clock, in %reset: !firrtl.uint<1>) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @BadName
// CHECK-SAME: in %reset: !firrtl.uint<1>,
// CHECK-SAME: in %clock: !firrtl.clock
// CHECK-SAME: in %existingReset: !firrtl.uint<1>
// CHECK: %reg = firrtl.regreset %clock, %reset, %c0_ui8
firrtl.module @BadName(in %clock: !firrtl.clock, in %existingReset: !firrtl.uint<1>) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @BadType
// CHECK-SAME: in %reset_0: !firrtl.uint<1>
// CHECK-SAME: in %clock: !firrtl.clock
// CHECK-SAME: in %reset: !firrtl.asyncreset
// CHECK: %reg = firrtl.regreset %clock, %reset_0, %c0_ui8
firrtl.module @BadType(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @ReusePorts
firrtl.module @ReusePortsSync(in %clock: !firrtl.clock, in %reset: !firrtl.uint<1>) attributes {
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "sync"}]]} {
// CHECK: %child_clock, %child_reset = firrtl.instance child
// CHECK: firrtl.matchingconnect %child_reset, %reset
// CHECK: %badName_reset, %badName_clock, %badName_existingReset = firrtl.instance badName
// CHECK: firrtl.matchingconnect %badName_reset, %reset
// CHECK: %badType_reset_0, %badType_clock, %badType_reset = firrtl.instance badType
// CHECK: firrtl.matchingconnect %badType_reset_0, %reset
%child_clock, %child_reset = firrtl.instance child @Child(in clock: !firrtl.clock, in reset: !firrtl.uint<1>)
%badName_clock, %badName_existingReset = firrtl.instance badName @BadName(in clock: !firrtl.clock, in existingReset: !firrtl.uint<1>)
%badType_clock, %badType_reset = firrtl.instance badType @BadType(in clock: !firrtl.clock, in reset: !firrtl.asyncreset)
}
}
// -----
// Infer async reset: nested
firrtl.circuit "FullAsyncNested" {
// CHECK-LABEL: firrtl.module @FullAsyncNestedDeeper
firrtl.module @FullAsyncNestedDeeper(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %io_in: !firrtl.uint<8>, out %io_out: !firrtl.uint<8>) {
%c1_ui1 = firrtl.constant 1 : !firrtl.uint<1>
// CHECK: %io_out_REG = firrtl.regreset %clock, %reset, %c1_ui1
%io_out_REG = firrtl.regreset %clock, %reset, %c1_ui1 : !firrtl.clock, !firrtl.asyncreset, !firrtl.uint<1>, !firrtl.uint<8>
firrtl.matchingconnect %io_out_REG, %io_in : !firrtl.uint<8>
firrtl.matchingconnect %io_out, %io_out_REG : !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @FullAsyncNestedChild
firrtl.module @FullAsyncNestedChild(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %io_in: !firrtl.uint<8>, out %io_out: !firrtl.uint<8>) {
%inst_clock, %inst_reset, %inst_io_in, %inst_io_out = firrtl.instance inst @FullAsyncNestedDeeper(in clock: !firrtl.clock, in reset: !firrtl.asyncreset, in io_in: !firrtl.uint<8>, out io_out: !firrtl.uint<8>)
firrtl.matchingconnect %inst_clock, %clock : !firrtl.clock
firrtl.matchingconnect %inst_reset, %reset : !firrtl.asyncreset
firrtl.matchingconnect %inst_io_in, %io_in : !firrtl.uint<8>
// CHECK: %io_out_REG = firrtl.regreset %clock, %reset, %c0_ui8
%io_out_REG = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
// CHECK: %io_out_REG_NO = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
%io_out_REG_NO = firrtl.reg %clock {annotations = [{class = "sifive.enterprise.firrtl.ExcludeMemFromMemToRegOfVec"}]}: !firrtl.clock, !firrtl.uint<8>
firrtl.matchingconnect %io_out_REG, %io_in : !firrtl.uint<8>
%0 = firrtl.add %io_out_REG, %inst_io_out : (!firrtl.uint<8>, !firrtl.uint<8>) -> !firrtl.uint<9>
%1 = firrtl.bits %0 7 to 0 : (!firrtl.uint<9>) -> !firrtl.uint<8>
firrtl.matchingconnect %io_out, %1 : !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @FullAsyncNested
firrtl.module @FullAsyncNested(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %io_in: !firrtl.uint<8>, out %io_out: !firrtl.uint<8>) attributes {
portAnnotations=[[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "async"}], [], []] } {
%inst_clock, %inst_reset, %inst_io_in, %inst_io_out = firrtl.instance inst @FullAsyncNestedChild(in clock: !firrtl.clock, in reset: !firrtl.asyncreset, in io_in: !firrtl.uint<8>, out io_out: !firrtl.uint<8>)
firrtl.matchingconnect %inst_clock, %clock : !firrtl.clock
firrtl.matchingconnect %inst_reset, %reset : !firrtl.asyncreset
firrtl.matchingconnect %io_out, %inst_io_out : !firrtl.uint<8>
firrtl.matchingconnect %inst_io_in, %io_in : !firrtl.uint<8>
}
}
// -----
// Infer async reset: excluded
// TODO: Check that no extraReset port present
firrtl.circuit "FullAsyncExcluded" {
// CHECK-LABEL: firrtl.module @FullAsyncExcludedChild
// CHECK-SAME: (in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %io_in: !firrtl.uint<8>, out %io_out: !firrtl.uint<8>)
firrtl.module @FullAsyncExcludedChild(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %io_in: !firrtl.uint<8>, out %io_out: !firrtl.uint<8>) attributes {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} {
// CHECK: %io_out_REG = firrtl.reg %clock
%io_out_REG = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
firrtl.matchingconnect %io_out_REG, %io_in : !firrtl.uint<8>
firrtl.matchingconnect %io_out, %io_out_REG : !firrtl.uint<8>
}
// CHECK-LABEL: firrtl.module @FullAsyncExcluded
firrtl.module @FullAsyncExcluded(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %io_in: !firrtl.uint<8>, out %io_out: !firrtl.uint<8>, in %extraReset: !firrtl.asyncreset) attributes {
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "async"}]]} {
// CHECK: %inst_clock, %inst_reset, %inst_io_in, %inst_io_out = firrtl.instance inst @FullAsyncExcludedChild
%inst_clock, %inst_reset, %inst_io_in, %inst_io_out = firrtl.instance inst @FullAsyncExcludedChild(in clock: !firrtl.clock, in reset: !firrtl.asyncreset, in io_in: !firrtl.uint<8>, out io_out: !firrtl.uint<8>)
firrtl.matchingconnect %inst_clock, %clock : !firrtl.clock
firrtl.matchingconnect %inst_reset, %reset : !firrtl.asyncreset
firrtl.matchingconnect %io_out, %inst_io_out : !firrtl.uint<8>
firrtl.matchingconnect %inst_io_in, %io_in : !firrtl.uint<8>
}
}
// -----
// Local wire as async reset should be moved before all its uses.
firrtl.circuit "WireShouldDominate" {
// CHECK-LABEL: firrtl.module @WireShouldDominate
firrtl.module @WireShouldDominate(in %clock: !firrtl.clock) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
%localReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK-NEXT: %localReset = firrtl.wire
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
}
}
// -----
// Local node as async reset should be moved before all its uses if its input
// value dominates the target location in the module.
firrtl.circuit "MovableNodeShouldDominate" {
// CHECK-LABEL: firrtl.module @MovableNodeShouldDominate
firrtl.module @MovableNodeShouldDominate(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // does not block move of node
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK-NEXT: %0 = firrtl.asAsyncReset %ui1
// CHECK-NEXT: %localReset = firrtl.node sym @theReset %0
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
}
}
// -----
// Local node as async reset should be replaced by a wire and moved before all
// its uses if its input value does not dominate the target location in the
// module.
firrtl.circuit "UnmovableNodeShouldDominate" {
// CHECK-LABEL: firrtl.module @UnmovableNodeShouldDominate
firrtl.module @UnmovableNodeShouldDominate(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK-NEXT: %localReset = firrtl.wire sym @theReset
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
// CHECK-NEXT: %0 = firrtl.asAsyncReset %ui1
// CHECK-NEXT: %1 = firrtl.node %0 :
// CHECK-NEXT: firrtl.matchingconnect %localReset, %1 :
}
}
// -----
// Same test as above, ensure works w/forceable node.
firrtl.circuit "UnmovableForceableNodeShouldDominate" {
// CHECK-LABEL: firrtl.module @UnmovableForceableNodeShouldDominate
firrtl.module @UnmovableForceableNodeShouldDominate(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
%localReset, %ref = firrtl.node sym @theReset %0 forceable {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK-NEXT: %localReset, %{{.+}} = firrtl.wire sym @theReset
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
// CHECK-NEXT: %0 = firrtl.asAsyncReset %ui1
// CHECK-NEXT: %1:2 = firrtl.node %0 forceable
// CHECK-NEXT: firrtl.matchingconnect %localReset, %1#0
}
}
// -----
// Move of local async resets should work across blocks.
firrtl.circuit "MoveAcrossBlocks1" {
// CHECK-LABEL: firrtl.module @MoveAcrossBlocks1
firrtl.module @MoveAcrossBlocks1(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
// <-- should move reset here
firrtl.when %ui1 : !firrtl.uint<1> {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
}
firrtl.when %ui1 : !firrtl.uint<1> {
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
}
// CHECK-NEXT: %localReset = firrtl.wire
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
// CHECK-NEXT: }
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
// CHECK-NEXT: [[TMP:%.+]] = firrtl.asAsyncReset %ui1
// CHECK-NEXT: [[TMP2:%.+]] = firrtl.node [[TMP]] : !firrtl.asyncreset
// CHECK-NEXT: firrtl.matchingconnect %localReset, [[TMP2]]
// CHECK-NEXT: }
}
}
// -----
firrtl.circuit "MoveAcrossBlocks2" {
// CHECK-LABEL: firrtl.module @MoveAcrossBlocks2
firrtl.module @MoveAcrossBlocks2(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
// <-- should move reset here
firrtl.when %ui1 : !firrtl.uint<1> {
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
}
firrtl.when %ui1 : !firrtl.uint<1> {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
}
// CHECK-NEXT: %localReset = firrtl.wire
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
// CHECK-NEXT: [[TMP:%.+]] = firrtl.asAsyncReset %ui1
// CHECK-NEXT: [[TMP2:%.+]] = firrtl.node [[TMP]] : !firrtl.asyncreset
// CHECK-NEXT: firrtl.matchingconnect %localReset, [[TMP2]]
// CHECK-NEXT: }
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
// CHECK-NEXT: }
}
}
// -----
firrtl.circuit "MoveAcrossBlocks3" {
// CHECK-LABEL: firrtl.module @MoveAcrossBlocks3
firrtl.module @MoveAcrossBlocks3(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
// <-- should move reset here
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
firrtl.when %ui1 : !firrtl.uint<1> {
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
}
// CHECK-NEXT: %localReset = firrtl.wire
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
// CHECK-NEXT: [[TMP:%.+]] = firrtl.asAsyncReset %ui1
// CHECK-NEXT: [[TMP2:%.+]] = firrtl.node [[TMP]] : !firrtl.asyncreset
// CHECK-NEXT: firrtl.matchingconnect %localReset, [[TMP2]]
// CHECK-NEXT: }
}
}
// -----
firrtl.circuit "MoveAcrossBlocks4" {
// CHECK-LABEL: firrtl.module @MoveAcrossBlocks4
firrtl.module @MoveAcrossBlocks4(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
// <-- should move reset here
firrtl.when %ui1 : !firrtl.uint<1> {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
}
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK-NEXT: %localReset = firrtl.wire
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
// CHECK-NEXT: }
// CHECK-NEXT: [[TMP:%.+]] = firrtl.asAsyncReset %ui1
// CHECK-NEXT: [[TMP2:%.+]] = firrtl.node [[TMP]] : !firrtl.asyncreset
// CHECK-NEXT: firrtl.matchingconnect %localReset, [[TMP2]]
}
}
// -----
firrtl.circuit "SubAccess" {
firrtl.module @SubAccess(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %init: !firrtl.uint<1>, in %in: !firrtl.uint<8>, in %extraReset: !firrtl.asyncreset ) attributes {
// CHECK-LABEL: firrtl.module @SubAccess
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "async"}]]} {
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<2>
%arr = firrtl.wire : !firrtl.vector<uint<8>, 1>
%reg6 = firrtl.regreset %clock, %init, %c1_ui8 : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>
%2 = firrtl.subaccess %arr[%reg6] : !firrtl.vector<uint<8>, 1>, !firrtl.uint<2>
firrtl.matchingconnect %2, %in : !firrtl.uint<8>
// CHECK: %reg6 = firrtl.regreset %clock, %extraReset, %c0_ui2 : !firrtl.clock, !firrtl.asyncreset, !firrtl.const.uint<2>, !firrtl.uint<2>
// CHECK-NEXT: %0 = firrtl.mux(%init, %c1_ui2, %reg6)
// CHECK: firrtl.matchingconnect %reg6, %0
// CHECK-NEXT: %[[v0:.+]] = firrtl.subaccess %arr[%reg6] : !firrtl.vector<uint<8>, 1>, !firrtl.uint<2>
// CHECK-NEXT: firrtl.matchingconnect %[[v0]], %in : !firrtl.uint<8>
}
}
// -----
// This is a regression check to ensure that a zero-width register gets a proper
// reset value.
// CHECK-LABEL: firrtl.module @ZeroWidthRegister
firrtl.circuit "ZeroWidthRegister" {
firrtl.module @ZeroWidthRegister(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<0>
// CHECK-NEXT: [[TMP:%.+]] = firrtl.constant 0 : !firrtl.const.uint<0>
// CHECK-NEXT: %reg = firrtl.regreset %clock, %reset, [[TMP]]
}
}
// -----
// Every module which is contained inside a reset domain should be annotated as
// such, so that internal registers can be lowered later correctly.
// https://github.com/llvm/circt/issues/7675
firrtl.circuit "top" {
// CHECK: firrtl.module private @test
// CHECK-SAME: annotations = [{class = "circt.FullResetAnnotation"}]
firrtl.module private @test(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset, in %in: !firrtl.uint<8>, out %out: !firrtl.uint<8>) {
%resetvalue = firrtl.wire : !firrtl.uint<8>
%invalid_ui8 = firrtl.invalidvalue : !firrtl.uint<8>
firrtl.matchingconnect %resetvalue, %invalid_ui8 : !firrtl.uint<8>
%reg1 = firrtl.regreset %clock, %reset, %resetvalue : !firrtl.clock, !firrtl.asyncreset, !firrtl.uint<8>, !firrtl.uint<8>
firrtl.matchingconnect %reg1, %in : !firrtl.uint<8>
firrtl.matchingconnect %out, %reg1 : !firrtl.uint<8>
}
// CHECK: firrtl.module @top
// CHECK-SAME: annotations = [{class = "circt.FullResetAnnotation"}]
firrtl.module @top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset [{class = "circt.FullResetAnnotation", resetType = "async"}], in %in: !firrtl.uint<8>, out %out: !firrtl.uint<8>) attributes {convention = #firrtl<convention scalarized>} {
%child_clock, %child_reset, %child_in, %child_out = firrtl.instance child @test(in clock: !firrtl.clock, in reset: !firrtl.asyncreset, in in: !firrtl.uint<8>, out out: !firrtl.uint<8>)
firrtl.matchingconnect %child_clock, %clock : !firrtl.clock
firrtl.matchingconnect %child_reset, %reset : !firrtl.asyncreset
firrtl.matchingconnect %child_in, %in : !firrtl.uint<8>
firrtl.matchingconnect %out, %child_out : !firrtl.uint<8>
}
}
// -----
// Check that unaffected fields ("data") are not being affected by width
// inference. See https://github.com/llvm/circt/issues/2857.
// CHECK-LABEL: firrtl.module @ZeroLengthVectorInBundle1
firrtl.circuit "ZeroLengthVectorInBundle1" {
firrtl.module @ZeroLengthVectorInBundle1(out %out: !firrtl.bundle<resets: vector<reset, 0>, data flip: uint<3>>) {
%0 = firrtl.subfield %out[resets] : !firrtl.bundle<resets: vector<reset, 0>, data flip: uint<3>>
%invalid = firrtl.invalidvalue : !firrtl.vector<reset, 0>
firrtl.matchingconnect %0, %invalid : !firrtl.vector<reset, 0>
// CHECK-NEXT: %0 = firrtl.subfield %out[resets] : !firrtl.bundle<resets: vector<uint<1>, 0>, data flip: uint<3>>
// CHECK-NEXT: %invalid = firrtl.invalidvalue : !firrtl.vector<uint<1>, 0>
// CHECK-NEXT: firrtl.matchingconnect %0, %invalid : !firrtl.vector<uint<1>, 0>
}
}
// -----
// CHECK-LABEL: firrtl.module @ZeroLengthVectorInBundle2
firrtl.circuit "ZeroLengthVectorInBundle2" {
firrtl.module @ZeroLengthVectorInBundle2(out %out: !firrtl.bundle<resets: vector<bundle<a: reset>, 0>, data flip: uint<3>>) {
%0 = firrtl.subfield %out[resets] : !firrtl.bundle<resets: vector<bundle<a: reset>, 0>, data flip: uint<3>>
%invalid = firrtl.invalidvalue : !firrtl.vector<bundle<a: reset>, 0>
firrtl.matchingconnect %0, %invalid : !firrtl.vector<bundle<a: reset>, 0>
// CHECK-NEXT: %0 = firrtl.subfield %out[resets] : !firrtl.bundle<resets: vector<bundle<a: uint<1>>, 0>, data flip: uint<3>>
// CHECK-NEXT: %invalid = firrtl.invalidvalue : !firrtl.vector<bundle<a: uint<1>>, 0>
// CHECK-NEXT: firrtl.matchingconnect %0, %invalid : !firrtl.vector<bundle<a: uint<1>>, 0>
}
}
// -----
// Resets nested underneath a zero-length vector should infer to `UInt<1>`.
// CHECK-LABEL: firrtl.module @ZeroVecBundle
// CHECK-SAME: in %a: !firrtl.vector<bundle<x: uint<1>>, 0>
// CHECK-SAME: out %b: !firrtl.vector<bundle<x: uint<1>>, 0>
firrtl.circuit "ZeroVecBundle" {
firrtl.module @ZeroVecBundle(in %a: !firrtl.vector<bundle<x: uint<1>>, 0>, out %b: !firrtl.vector<bundle<x: reset>, 0>) {
%w = firrtl.wire : !firrtl.vector<bundle<x: reset>, 0>
firrtl.matchingconnect %b, %w : !firrtl.vector<bundle<x: reset>, 0>
// CHECK-NEXT: %w = firrtl.wire : !firrtl.vector<bundle<x: uint<1>>, 0>
// CHECK-NEXT: firrtl.matchingconnect %b, %w : !firrtl.vector<bundle<x: uint<1>>, 0>
}
}
// -----
// Resets directly in a zero-length vector should infer to `UInt<1>`.
// CHECK-LABEL: firrtl.module @ZeroVec
// CHECK-SAME: in %a: !firrtl.bundle<x: vector<uint<1>, 0>>
// CHECK-SAME: out %b: !firrtl.bundle<x: vector<uint<1>, 0>>
firrtl.circuit "ZeroVec" {
firrtl.module @ZeroVec(in %a: !firrtl.bundle<x: vector<reset, 0>>, out %b: !firrtl.bundle<x: vector<reset, 0>>) {
firrtl.matchingconnect %b, %a : !firrtl.bundle<x: vector<reset, 0>>
// CHECK-NEXT: firrtl.matchingconnect %b, %a : !firrtl.bundle<x: vector<uint<1>, 0>>
}
}
// -----
// CHECK-LABEL: "RefReset"
firrtl.circuit "RefReset" {
// CHECK-LABEL: firrtl.module private @SendReset
// CHECK-SAME: in %r: !firrtl.asyncreset
// CHECK-SAME: out %ref: !firrtl.probe<asyncreset>
// CHECK-NEXT: send %r : !firrtl.asyncreset
// CHECK-NEXT: probe<asyncreset>
firrtl.module private @SendReset(in %r: !firrtl.reset, out %ref: !firrtl.probe<reset>) {
%ref_r = firrtl.ref.send %r : !firrtl.reset
firrtl.ref.define %ref, %ref_r : !firrtl.probe<reset>
}
// CHECK-LABEL: firrtl.module @RefReset
// CHECK-NEXT: in r: !firrtl.asyncreset
// CHECK-SAME: out ref: !firrtl.probe<asyncreset>
// CHECK-NEXT: !firrtl.asyncreset
// CHECK-NEXT: %s_ref : !firrtl.probe<asyncreset>
firrtl.module @RefReset(in %r: !firrtl.asyncreset) {
%s_r, %s_ref = firrtl.instance s @SendReset(in r: !firrtl.reset, out ref: !firrtl.probe<reset>)
firrtl.connect %s_r, %r : !firrtl.reset, !firrtl.asyncreset
%reset = firrtl.ref.resolve %s_ref : !firrtl.probe<reset>
}
}
// -----
// CHECK-LABEL: "RefCastReset"
firrtl.circuit "RefCastReset" {
// CHECK-LABEL: firrtl.module private @SendCastReset
// CHECK-SAME: in %r: !firrtl.asyncreset
// CHECK-SAME: out %ref: !firrtl.probe<asyncreset>
// CHECK-NEXT: send %r : !firrtl.asyncreset
// CHECK-NEXT: probe<asyncreset>
firrtl.module private @SendCastReset(in %r: !firrtl.asyncreset, out %ref: !firrtl.probe<reset>) {
%ref_r = firrtl.ref.send %r : !firrtl.asyncreset
%ref_r_cast = firrtl.ref.cast %ref_r : (!firrtl.probe<asyncreset>) -> !firrtl.probe<reset>
firrtl.ref.define %ref, %ref_r_cast : !firrtl.probe<reset>
}
// CHECK-LABEL: firrtl.module @RefCastReset
// CHECK-NEXT: in r: !firrtl.asyncreset
// CHECK-SAME: out ref: !firrtl.probe<asyncreset>
// CHECK-NEXT: : !firrtl.asyncreset
// CHECK-NEXT: %s_ref : !firrtl.probe<asyncreset>
firrtl.module @RefCastReset(in %r: !firrtl.asyncreset) {
%s_r, %s_ref = firrtl.instance s @SendCastReset(in r: !firrtl.asyncreset, out ref: !firrtl.probe<reset>)
firrtl.matchingconnect %s_r, %r : !firrtl.asyncreset
%reset = firrtl.ref.resolve %s_ref : !firrtl.probe<reset>
}
}
// -----
// CHECK-LABEL: "RefCastAggReset"
firrtl.circuit "RefCastAggReset" {
// CHECK-LABEL: firrtl.module private @ResetAggSource
// CHECK-SAME: in %r: !firrtl.asyncreset,
// CHECK-SAME: out %p: !firrtl.rwprobe<bundle<a: asyncreset, b: uint<1>>>,
// CHECK-SAME: out %pconst: !firrtl.probe<bundle<a: asyncreset, b: const.uint<1>>>)
// CHECK-NOT: : {{(const\.)?reset}}
firrtl.module private @ResetAggSource(in %r: !firrtl.asyncreset, out %p: !firrtl.rwprobe<bundle<a: reset, b: reset>>, out %pconst: !firrtl.probe<bundle<a: reset, b: const.reset>>) {
%x = firrtl.wire : !firrtl.reset
%0 = firrtl.resetCast %r : (!firrtl.asyncreset) -> !firrtl.reset
firrtl.matchingconnect %x, %0 : !firrtl.reset
%c0_ui1 = firrtl.constant 0 : !firrtl.const.uint<1>
%zero = firrtl.node %c0_ui1 : !firrtl.const.uint<1>
%bundle, %bundle_ref = firrtl.wire forceable : !firrtl.bundle<a: reset, b: reset>, !firrtl.rwprobe<bundle<a: reset, b: reset>>
%1 = firrtl.subfield %bundle[b] : !firrtl.bundle<a: reset, b: reset>
%2 = firrtl.subfield %bundle[a] : !firrtl.bundle<a: reset, b: reset>
firrtl.matchingconnect %2, %x : !firrtl.reset
%3 = firrtl.resetCast %zero : (!firrtl.const.uint<1>) -> !firrtl.const.reset
%4 = firrtl.constCast %3 : (!firrtl.const.reset) -> !firrtl.reset
firrtl.matchingconnect %1, %4 : !firrtl.reset
firrtl.ref.define %p, %bundle_ref : !firrtl.rwprobe<bundle<a: reset, b: reset>>
%bundle_const = firrtl.wire : !firrtl.bundle<a: reset, b: const.reset>
%5 = firrtl.subfield %bundle_const[b] : !firrtl.bundle<a: reset, b: const.reset>
%6 = firrtl.subfield %bundle_const[a] : !firrtl.bundle<a: reset, b: const.reset>
firrtl.matchingconnect %6, %x : !firrtl.reset
firrtl.matchingconnect %5, %3 : !firrtl.const.reset
%7 = firrtl.ref.send %bundle_const : !firrtl.bundle<a: reset, b: const.reset>
firrtl.ref.define %pconst, %7 : !firrtl.probe<bundle<a: reset, b: const.reset>>
}
// CHECK-LABEL: firrtl.module @RefCastAggReset
// CHECK-SAME: in %r: !firrtl.asyncreset,
// CHECK-SAME: out %a: !firrtl.probe<asyncreset>,
// CHECK-SAME: out %b: !firrtl.probe<uint<1>>,
// CHECK-SAME: out %pconst: !firrtl.probe<bundle<a: asyncreset, b: const.uint<1>>>)
// CHECK-NOT: : {{(const\.)?reset}}
firrtl.module @RefCastAggReset(in %r: !firrtl.asyncreset, out %a: !firrtl.probe<reset>, out %b: !firrtl.probe<reset>, out %pconst: !firrtl.probe<bundle<a: reset, b: const.reset>>) {
%s_r, %s_p, %s_pconst = firrtl.instance s @ResetAggSource(in r: !firrtl.asyncreset, out p: !firrtl.rwprobe<bundle<a: reset, b: reset>>, out pconst: !firrtl.probe<bundle<a: reset, b: const.reset>>)
%0 = firrtl.ref.sub %s_p[1] : !firrtl.rwprobe<bundle<a: reset, b: reset>>
%1 = firrtl.ref.sub %s_p[0] : !firrtl.rwprobe<bundle<a: reset, b: reset>>
firrtl.matchingconnect %s_r, %r : !firrtl.asyncreset
%2 = firrtl.ref.cast %1 : (!firrtl.rwprobe<reset>) -> !firrtl.probe<reset>
firrtl.ref.define %a, %2 : !firrtl.probe<reset>
%3 = firrtl.ref.cast %0 : (!firrtl.rwprobe<reset>) -> !firrtl.probe<reset>
firrtl.ref.define %b, %3 : !firrtl.probe<reset>
firrtl.ref.define %pconst, %s_pconst : !firrtl.probe<bundle<a: reset, b: const.reset>>
}
}
// -----
// Check resets are inferred through references to bundles w/flips.
// CHECK-LABEL: "RefResetBundle"
firrtl.circuit "RefResetBundle" {
// CHECK-LABEL: firrtl.module @RefResetBundle
// CHECK-NOT: firrtl.reset
firrtl.module @RefResetBundle(in %driver: !firrtl.asyncreset, out %out: !firrtl.bundle<a: reset, b: reset>) {
%r = firrtl.wire : !firrtl.bundle<a: reset, b flip: reset>
%ref_r = firrtl.ref.send %r : !firrtl.bundle<a: reset, b flip: reset>
%reset = firrtl.ref.resolve %ref_r : !firrtl.probe<bundle<a: reset, b: reset>>
firrtl.matchingconnect %out, %reset : !firrtl.bundle<a: reset, b: reset>
%r_a = firrtl.subfield %r[a] : !firrtl.bundle<a: reset, b flip: reset>
%r_b = firrtl.subfield %r[b] : !firrtl.bundle<a: reset, b flip: reset>
firrtl.connect %r_a, %driver : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r_b, %driver : !firrtl.reset, !firrtl.asyncreset
}
}
// -----
// Check resets are inferred through ref.sub.
// CHECK-LABEL: "RefResetSub"
firrtl.circuit "RefResetSub" {
// CHECK-LABEL: firrtl.module @RefResetSub
// CHECK-NOT: firrtl.reset
firrtl.module @RefResetSub(in %driver: !firrtl.asyncreset, out %out_a : !firrtl.reset, out %out_b: !firrtl.vector<reset,2>) {
%r = firrtl.wire : !firrtl.bundle<a: reset, b flip: vector<reset, 2>>
%ref_r = firrtl.ref.send %r : !firrtl.bundle<a: reset, b flip: vector<reset, 2>>
%ref_r_a = firrtl.ref.sub %ref_r[0] : !firrtl.probe<bundle<a: reset, b : vector<reset, 2>>>
%reset_a = firrtl.ref.resolve %ref_r_a : !firrtl.probe<reset>
%ref_r_b = firrtl.ref.sub %ref_r[1] : !firrtl.probe<bundle<a: reset, b : vector<reset, 2>>>
%reset_b = firrtl.ref.resolve %ref_r_b : !firrtl.probe<vector<reset, 2>>
firrtl.matchingconnect %out_a, %reset_a : !firrtl.reset
firrtl.matchingconnect %out_b, %reset_b : !firrtl.vector<reset, 2>
%r_a = firrtl.subfield %r[a] : !firrtl.bundle<a: reset, b flip: vector<reset, 2>>
%r_b = firrtl.subfield %r[b] : !firrtl.bundle<a: reset, b flip: vector<reset, 2>>
%r_b_0 = firrtl.subindex %r_b[0] : !firrtl.vector<reset, 2>
%r_b_1 = firrtl.subindex %r_b[1] : !firrtl.vector<reset, 2>
firrtl.connect %r_a, %driver : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r_b_0, %driver : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r_b_1, %driver : !firrtl.reset, !firrtl.asyncreset
}
}
// -----
// CHECK-LABEL: "ConstReset"
firrtl.circuit "ConstReset" {
// CHECK-LABEL: firrtl.module private @InfersConstAsync(in %r: !firrtl.const.asyncreset)
firrtl.module private @InfersConstAsync(in %r: !firrtl.const.reset) {}
// CHECK-LABEL: firrtl.module private @InfersConstSync(in %r: !firrtl.const.uint<1>)
firrtl.module private @InfersConstSync(in %r: !firrtl.const.reset) {}
// CHECK-LABEL: firrtl.module private @InfersAsync(in %r: !firrtl.asyncreset)
firrtl.module private @InfersAsync(in %r: !firrtl.reset) {}
// CHECK-LABEL: firrtl.module private @InfersSync(in %r: !firrtl.uint<1>)
firrtl.module private @InfersSync(in %r: !firrtl.reset) {}
firrtl.module @ConstReset(in %async: !firrtl.const.asyncreset, in %sync: !firrtl.const.uint<1>) {
%constAsyncTarget = firrtl.instance infersConstAsync @InfersConstAsync(in r: !firrtl.const.reset)
%constSyncTarget = firrtl.instance infersConstSync @InfersConstSync(in r: !firrtl.const.reset)
%asyncTarget = firrtl.instance infersAsync @InfersAsync(in r: !firrtl.reset)
%syncTarget = firrtl.instance infersSync @InfersSync(in r: !firrtl.reset)
firrtl.connect %constAsyncTarget, %async : !firrtl.const.reset, !firrtl.const.asyncreset
firrtl.connect %constSyncTarget, %sync : !firrtl.const.reset, !firrtl.const.uint<1>
firrtl.connect %asyncTarget, %async : !firrtl.reset, !firrtl.const.asyncreset
firrtl.connect %syncTarget, %sync : !firrtl.reset, !firrtl.const.uint<1>
}
}
// -----
// CHECK-LABEL: "ConstAggReset"
firrtl.circuit "ConstAggReset" {
// CHECK-LABEL: module @ConstAggReset
// CHECK-NOT: : reset
firrtl.module @ConstAggReset(in %in: !firrtl.const.bundle<a: reset, b: uint<1>>, out %out: !firrtl.bundle<a: asyncreset>, out %out2: !firrtl.bundle<a: reset, b: uint<1>>) {
%out_a = firrtl.subfield %out[a] : !firrtl.bundle<a: asyncreset>
%in_a = firrtl.subfield %in[a] : !firrtl.const.bundle<a: reset, b: uint<1>>
%in_a_asyncreset = firrtl.resetCast %in_a : (!firrtl.const.reset) -> !firrtl.const.asyncreset
%in_a_asyncreset_noconst = firrtl.constCast %in_a_asyncreset : (!firrtl.const.asyncreset) -> !firrtl.asyncreset
firrtl.matchingconnect %out_a, %in_a_asyncreset_noconst : !firrtl.asyncreset
%in_noconst = firrtl.constCast %in : (!firrtl.const.bundle<a: reset, b: uint<1>>) -> !firrtl.bundle<a: reset, b : uint<1>>
firrtl.matchingconnect %out2, %in_noconst : !firrtl.bundle<a: reset, b: uint<1>>
}
}
// -----
// CHECK-LABEL: "ConstAggCastReset"
firrtl.circuit "ConstAggCastReset" {
// CHECK-LABEL: module @ConstAggCastReset
// CHECK-NOT: : reset
firrtl.module @ConstAggCastReset(in %in: !firrtl.const.bundle<a: reset, b: uint<1>>, out %out: !firrtl.bundle<a: asyncreset>, out %out2: !firrtl.bundle<a: reset, b: uint<1>>) {
%out_a = firrtl.subfield %out[a] : !firrtl.bundle<a: asyncreset>
%in_a = firrtl.subfield %in[a] : !firrtl.const.bundle<a: reset, b: uint<1>>
// CHECK: constCast %{{.+}} : (!firrtl.const.asyncreset) -> !firrtl.asyncreset
%in_a_noconst = firrtl.constCast %in_a : (!firrtl.const.reset) -> !firrtl.reset
%in_a_asyncreset = firrtl.resetCast %in_a_noconst : (!firrtl.reset) -> !firrtl.asyncreset
// CHECK-NEXT: matchingconnect
firrtl.matchingconnect %out_a, %in_a_asyncreset : !firrtl.asyncreset
// CHECK-NOT: : reset
%in_noconst = firrtl.constCast %in : (!firrtl.const.bundle<a: reset, b: uint<1>>) -> !firrtl.bundle<a: reset, b : uint<1>>
firrtl.matchingconnect %out2, %in_noconst : !firrtl.bundle<a: reset, b: uint<1>>
}
}
// -----
// Check resets are inferred for forceable ops.
// CHECK-LABEL: "InferToRWProbe"
firrtl.circuit "InferToRWProbe" {
// CHECK-LABEL: firrtl.module @InferToRWProbe
// CHECK-NOT: firrtl.reset
firrtl.module @InferToRWProbe(in %driver: !firrtl.asyncreset, out %out: !firrtl.bundle<a: reset, b: reset>) {
%r, %r_rw = firrtl.wire forceable : !firrtl.bundle<a: reset, b flip: reset>, !firrtl.rwprobe<bundle<a: reset, b : reset>>
%reset = firrtl.ref.resolve %r_rw : !firrtl.rwprobe<bundle<a: reset, b: reset>>
firrtl.matchingconnect %out, %reset : !firrtl.bundle<a: reset, b: reset>
%r_a = firrtl.subfield %r[a] : !firrtl.bundle<a: reset, b flip: reset>
%r_b = firrtl.subfield %r[b] : !firrtl.bundle<a: reset, b flip: reset>
firrtl.connect %r_a, %driver : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r_b, %driver : !firrtl.reset, !firrtl.asyncreset
}
}
// -----
// Check resets are traced through nodes
// CHECK-LABEL: "TraceThroughNodes"
// CHECK-NOT: firrtl.reset
firrtl.circuit "TraceThroughNodes" {
firrtl.module @TraceThroughNodes(in %reset: !firrtl.asyncreset) {
// CHECK: %node = firrtl.node %localReset : !firrtl.asyncreset
// CHECK-NOT: firrtl.reset
%localReset = firrtl.wire : !firrtl.reset
firrtl.connect %localReset, %reset : !firrtl.reset, !firrtl.asyncreset
%node = firrtl.node %localReset : !firrtl.reset
%localReset2 = firrtl.wire : !firrtl.reset
firrtl.matchingconnect %localReset2, %node: !firrtl.reset
// CHECK: %node2 = firrtl.node %localReset2 : !firrtl.asyncreset
%node2 = firrtl.node %localReset2 : !firrtl.reset
}
}
// -----
// CHECK-LABEL: "RWProbeOp"
firrtl.circuit "RWProbeOp" {
// CHECK: %out: !firrtl.bundle<a: asyncreset, b: asyncreset>
// CHECK-SAME: %out2: !firrtl.asyncreset
firrtl.module @RWProbeOp(in %driver: !firrtl.asyncreset, out %out: !firrtl.bundle<a: reset, b: reset>, out %out2: !firrtl.reset) {
%r = firrtl.wire sym [<@r,0,public>,<@r_a,1,public>,<@r_b,2,public>] : !firrtl.bundle<a: reset, b flip: reset>
// CHECK-COUNT-2: <a: asyncreset, b flip: asyncreset>
%r_a = firrtl.subfield %r[a] : !firrtl.bundle<a: reset, b flip: reset>
%r_b = firrtl.subfield %r[b] : !firrtl.bundle<a: reset, b flip: reset>
// CHECK-COUNT-2: %driver : !firrtl.asyncreset
firrtl.connect %r_a, %driver : !firrtl.reset, !firrtl.asyncreset
firrtl.connect %r_b, %driver : !firrtl.reset, !firrtl.asyncreset
// CHECK-NEXT: rwprobe<asyncreset>
%r_a_rw = firrtl.ref.rwprobe <@RWProbeOp::@r_a> : !firrtl.rwprobe<reset>
// CHECK-NEXT: rwprobe<asyncreset>
%r_b_rw = firrtl.ref.rwprobe <@RWProbeOp::@r_b> : !firrtl.rwprobe<reset>
// CHECK-NEXT: rwprobe<bundle<a: asyncreset, b: asyncreset>>
%r_rw = firrtl.ref.rwprobe <@RWProbeOp::@r> : !firrtl.rwprobe<bundle<a: reset, b: reset>>
// CHECK-NEXT: rwprobe<asyncreset>
%r_b_read = firrtl.ref.resolve %r_b_rw : !firrtl.rwprobe<reset>
// CHECK-NEXT: rwprobe<bundle<a: asyncreset, b: asyncreset>>
%r_read = firrtl.ref.resolve %r_rw : !firrtl.rwprobe<bundle<a: reset, b: reset>>
// CHECK-NEXT: firrtl.asyncreset
firrtl.matchingconnect %out2, %r_b_read : !firrtl.reset
// CHECK-NEXT: bundle<a: asyncreset, b: asyncreset>
firrtl.matchingconnect %out, %r_read : !firrtl.bundle<a: reset, b: reset>
}
}
// -----
// CHECK-LABEL: "MovableNodeShouldDominateInstance"
firrtl.circuit "MovableNodeShouldDominateInstance" {
firrtl.module @MovableNodeShouldDominateInstance(in %clock: !firrtl.clock) {
%child_clock = firrtl.instance child @Child(in clock: !firrtl.clock)
firrtl.connect %child_clock, %clock : !firrtl.clock
%ui1 = firrtl.constant 1 : !firrtl.uint<1>
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset
%localReset = firrtl.node %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK: %localReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
// CHECK: %child_localReset, %child_clock = firrtl.instance child @Child(in localReset: !firrtl.asyncreset, in clock: !firrtl.clock
}
firrtl.module @Child(in %clock: !firrtl.clock) {
// CHECK: firrtl.regreset %clock, %localReset, %c0_ui8
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
}
}