mirror of https://github.com/llvm/circt.git
284 lines
14 KiB
MLIR
284 lines
14 KiB
MLIR
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-resets))' --verify-diagnostics --split-input-file %s
|
|
|
|
// Tests extracted from:
|
|
// - github.com/chipsalliance/firrtl:
|
|
// - test/scala/firrtlTests/InferResetsSpec.scala
|
|
// - github.com/sifive/$internal:
|
|
// - test/scala/firrtl/FullAsyncResetTransform.scala
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Reset Inference
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
// Should NOT allow last connect semantics to pick the right type for Reset
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "reset0" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %reset0: !firrtl.asyncreset, in %reset1: !firrtl.uint<1>, out %out: !firrtl.reset) {
|
|
%w0 = firrtl.wire : !firrtl.reset
|
|
%w1 = firrtl.wire : !firrtl.reset
|
|
firrtl.connect %w0, %reset0 : !firrtl.reset, !firrtl.asyncreset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %w1, %reset1 : !firrtl.reset, !firrtl.uint<1>
|
|
firrtl.connect %out, %w0 : !firrtl.reset, !firrtl.reset
|
|
firrtl.connect %out, %w1 : !firrtl.reset, !firrtl.reset
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should NOT support last connect semantics across whens
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "reset2" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %reset0: !firrtl.asyncreset, in %reset1: !firrtl.asyncreset, in %reset2: !firrtl.uint<1>, in %en: !firrtl.uint<1>, out %out: !firrtl.reset) {
|
|
%w0 = firrtl.wire : !firrtl.reset
|
|
%w1 = firrtl.wire : !firrtl.reset
|
|
%w2 = firrtl.wire : !firrtl.reset
|
|
firrtl.connect %w0, %reset0 : !firrtl.reset, !firrtl.asyncreset
|
|
firrtl.connect %w1, %reset1 : !firrtl.reset, !firrtl.asyncreset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %w2, %reset2 : !firrtl.reset, !firrtl.uint<1>
|
|
firrtl.connect %out, %w2 : !firrtl.reset, !firrtl.reset
|
|
firrtl.when %en : !firrtl.uint<1> {
|
|
firrtl.connect %out, %w0 : !firrtl.reset, !firrtl.reset
|
|
} else {
|
|
firrtl.connect %out, %w1 : !firrtl.reset, !firrtl.reset
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should not allow different Reset Types to drive a single Reset
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "reset0" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %reset0: !firrtl.asyncreset, in %reset1: !firrtl.uint<1>, in %en: !firrtl.uint<1>, out %out: !firrtl.reset) {
|
|
%w1 = firrtl.wire : !firrtl.reset
|
|
%w2 = firrtl.wire : !firrtl.reset
|
|
firrtl.connect %w1, %reset0 : !firrtl.reset, !firrtl.asyncreset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %w2, %reset1 : !firrtl.reset, !firrtl.uint<1>
|
|
firrtl.connect %out, %w1 : !firrtl.reset, !firrtl.reset
|
|
firrtl.when %en : !firrtl.uint<1> {
|
|
firrtl.connect %out, %w2 : !firrtl.reset, !firrtl.reset
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should error if a ResetType driving UInt<1> infers to AsyncReset
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "in" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %in: !firrtl.asyncreset, out %out: !firrtl.uint<1>) {
|
|
%w = firrtl.wire : !firrtl.reset
|
|
firrtl.connect %w, %in : !firrtl.reset, !firrtl.asyncreset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %out, %w : !firrtl.uint<1>, !firrtl.reset
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should error if a ResetType driving AsyncReset infers to UInt<1>
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "in" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %in: !firrtl.uint<1>, out %out: !firrtl.asyncreset) {
|
|
%w = firrtl.wire : !firrtl.reset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %w, %in : !firrtl.reset, !firrtl.uint<1>
|
|
firrtl.connect %out, %w : !firrtl.asyncreset, !firrtl.reset
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should not allow ResetType as an Input
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network never driven with concrete type}}
|
|
// expected-note @+1 {{here: }}
|
|
firrtl.module @top(in %in: !firrtl.bundle<foo: reset>, out %out: !firrtl.reset) {
|
|
// expected-note @+1 {{here: }}
|
|
%0 = firrtl.subfield %in[foo] : !firrtl.bundle<foo: reset>
|
|
firrtl.connect %out, %0 : !firrtl.reset, !firrtl.reset
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should not allow ResetType as an ExtModule output
|
|
firrtl.circuit "top" {
|
|
firrtl.extmodule @ext(out out: !firrtl.bundle<foo: reset>)
|
|
// expected-note @+1 {{here: }}
|
|
firrtl.module @top(out %out: !firrtl.reset) {
|
|
// expected-error @+2 {{reset network never driven with concrete type}}
|
|
// expected-note @+1 {{here: }}
|
|
%e_out = firrtl.instance e @ext(out out: !firrtl.bundle<foo: reset>)
|
|
// expected-note @+1 {{here: }}
|
|
%0 = firrtl.subfield %e_out[foo] : !firrtl.bundle<foo: reset>
|
|
firrtl.connect %out, %0 : !firrtl.reset, !firrtl.reset
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should not allow Vecs to infer different Reset Types
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "out[]" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %reset0: !firrtl.asyncreset, in %reset1: !firrtl.uint<1>, out %out: !firrtl.vector<reset, 2>) {
|
|
%0 = firrtl.subindex %out[0] : !firrtl.vector<reset, 2>
|
|
%1 = firrtl.subindex %out[1] : !firrtl.vector<reset, 2>
|
|
firrtl.connect %0, %reset0 : !firrtl.reset, !firrtl.asyncreset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %1, %reset1 : !firrtl.reset, !firrtl.uint<1>
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Should not allow an invalidated Wire to drive both a UInt<1> and an AsyncReset
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{reset network "in0" simultaneously connected to async and sync resets}}
|
|
// expected-note @+1 {{majority of connections to this reset are async}}
|
|
firrtl.module @top(in %in0: !firrtl.asyncreset, in %in1: !firrtl.uint<1>, out %out0: !firrtl.reset, out %out1: !firrtl.reset) {
|
|
%w = firrtl.wire : !firrtl.reset
|
|
%invalid_reset = firrtl.invalidvalue : !firrtl.reset
|
|
firrtl.connect %w, %invalid_reset : !firrtl.reset, !firrtl.reset
|
|
firrtl.connect %out0, %w : !firrtl.reset, !firrtl.reset
|
|
firrtl.connect %out1, %w : !firrtl.reset, !firrtl.reset
|
|
firrtl.connect %out0, %in0 : !firrtl.reset, !firrtl.asyncreset
|
|
// expected-note @+1 {{sync drive here:}}
|
|
firrtl.connect %out1, %in1 : !firrtl.reset, !firrtl.uint<1>
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Full Reset
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// -----
|
|
// Reset annotation cannot target module
|
|
firrtl.circuit "top" {
|
|
// expected-error @+1 {{'FullResetAnnotation' cannot target module; must target port or wire/node instead}}
|
|
firrtl.module @top() attributes {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} {
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Reset annotation resetType must match type of signal
|
|
firrtl.circuit "top" {
|
|
firrtl.module @top() {
|
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'async' must target async reset, but targets '!firrtl.uint<1>'}}
|
|
%innerReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.uint<1>
|
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'sync' must target sync reset, but targets '!firrtl.asyncreset'}}
|
|
%innerReset2 = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "sync"}]} : !firrtl.asyncreset
|
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'sync' must target sync reset, but targets '!firrtl.uint<2>'}}
|
|
%innerReset3 = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "sync"}]} : !firrtl.uint<2>
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Reset annotation cannot target reset signals which are inferred to the wrong type
|
|
firrtl.circuit "top" {
|
|
firrtl.module @top() {
|
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'async' must target async reset, but targets '!firrtl.uint<1>'}}
|
|
%innerReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.reset
|
|
%invalid = firrtl.invalidvalue : !firrtl.reset
|
|
firrtl.matchingconnect %innerReset, %invalid : !firrtl.reset
|
|
|
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'sync' must target sync reset, but targets '!firrtl.asyncreset'}}
|
|
%innerReset2 = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "sync"}]} : !firrtl.reset
|
|
%asyncWire = firrtl.wire : !firrtl.asyncreset
|
|
firrtl.connect %innerReset2, %asyncWire : !firrtl.reset, !firrtl.asyncreset
|
|
}
|
|
}
|
|
|
|
|
|
// -----
|
|
// Ignore reset annotation cannot target port
|
|
firrtl.circuit "top" {
|
|
// expected-error @+1 {{ExcludeFromFullResetAnnotation' cannot target port/wire/node; must target module instead}}
|
|
firrtl.module @top(in %reset: !firrtl.asyncreset) attributes {portAnnotations =[[{class = "circt.ExcludeFromFullResetAnnotation"}]]} {
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Ignore reset annotation cannot target wire/node
|
|
firrtl.circuit "top" {
|
|
firrtl.module @top() {
|
|
// expected-error @+1 {{ExcludeFromFullResetAnnotation' cannot target port/wire/node; must target module instead}}
|
|
%0 = firrtl.wire {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} : !firrtl.asyncreset
|
|
// expected-error @+1 {{ExcludeFromFullResetAnnotation' cannot target port/wire/node; must target module instead}}
|
|
%1 = firrtl.node %0 {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} : !firrtl.asyncreset
|
|
// expected-error @+1 {{reset annotations must target module, port, or wire/node}}
|
|
%2 = firrtl.asUInt %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : (!firrtl.asyncreset) -> !firrtl.uint<1>
|
|
// expected-error @+1 {{reset annotations must target module, port, or wire/node}}
|
|
%3 = firrtl.asUInt %0 {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} : (!firrtl.asyncreset) -> !firrtl.uint<1>
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Cannot have multiple reset annotations on a module
|
|
firrtl.circuit "top" {
|
|
// expected-error @+2 {{multiple reset annotations on module 'top'}}
|
|
// expected-note @+1 {{conflicting "circt.FullResetAnnotation":}}
|
|
firrtl.module @top(in %outerReset: !firrtl.asyncreset) attributes {portAnnotations = [[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
|
// expected-note @+1 {{conflicting "circt.FullResetAnnotation":}}
|
|
%innerReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
|
// expected-note @+1 {{conflicting "circt.FullResetAnnotation":}}
|
|
%anotherReset = firrtl.node %innerReset {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
|
}
|
|
}
|
|
|
|
// -----
|
|
// Multiple instances of same module cannot live in different reset domains
|
|
firrtl.circuit "Top" {
|
|
// expected-error @+1 {{module 'Foo' instantiated in different reset domains}}
|
|
firrtl.module @Foo(in %clock: !firrtl.clock) {
|
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
|
|
}
|
|
// expected-note @+1 {{reset domain 'otherReset' of module 'Child' declared here:}}
|
|
firrtl.module @Child(in %clock: !firrtl.clock, in %otherReset: !firrtl.asyncreset) attributes {portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
|
// expected-note @+1 {{instance 'child/inst' is in reset domain rooted at 'otherReset' of module 'Child'}}
|
|
%inst_clock = firrtl.instance inst @Foo(in clock: !firrtl.clock)
|
|
firrtl.connect %inst_clock, %clock : !firrtl.clock, !firrtl.clock
|
|
}
|
|
firrtl.module @Other(in %clock: !firrtl.clock) attributes {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} {
|
|
// expected-note @+1 {{instance 'other/inst' is in no reset domain}}
|
|
%inst_clock = firrtl.instance inst @Foo(in clock: !firrtl.clock)
|
|
firrtl.connect %inst_clock, %clock : !firrtl.clock, !firrtl.clock
|
|
}
|
|
// expected-note @+1 {{reset domain 'reset' of module 'Top' declared here:}}
|
|
firrtl.module @Top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
|
%child_clock, %child_otherReset = firrtl.instance child @Child(in clock: !firrtl.clock, in otherReset: !firrtl.asyncreset)
|
|
%other_clock = firrtl.instance other @Other(in clock: !firrtl.clock)
|
|
// expected-note @+1 {{instance 'foo' is in reset domain rooted at 'reset' of module 'Top'}}
|
|
%foo_clock = firrtl.instance foo @Foo(in clock: !firrtl.clock)
|
|
firrtl.connect %child_clock, %clock : !firrtl.clock, !firrtl.clock
|
|
firrtl.connect %other_clock, %clock : !firrtl.clock, !firrtl.clock
|
|
firrtl.connect %foo_clock, %clock : !firrtl.clock, !firrtl.clock
|
|
}
|
|
}
|
|
|
|
// -----
|
|
|
|
firrtl.circuit "UninferredReset" {
|
|
// expected-error @+2 {{a port "reset" with abstract reset type was unable to be inferred by InferResets}}
|
|
// expected-note @+1 {{the module with this uninferred reset port was defined here}}
|
|
firrtl.module @UninferredReset(in %reset: !firrtl.reset) {}
|
|
}
|
|
|
|
// -----
|
|
|
|
firrtl.circuit "UninferredRefReset" {
|
|
firrtl.module @UninferredRefReset() {}
|
|
// expected-error @+2 {{a port "reset" with abstract reset type was unable to be inferred by InferResets}}
|
|
// expected-note @+1 {{the module with this uninferred reset port was defined here}}
|
|
firrtl.module private @UninferredRefResetPriv(out %reset: !firrtl.probe<reset>) {}
|
|
}
|
|
|
|
// -----
|
|
// Invalid FullResetAnnotation resetType
|
|
firrtl.circuit "Top" {
|
|
// expected-error @+1 {{'FullResetAnnotation' requires resetType == 'sync' | 'async', but got resetType == "potato"}}
|
|
firrtl.module @Top(in %reset: !firrtl.asyncreset) attributes {portAnnotations = [[{class = "circt.FullResetAnnotation", resetType = "potato"}]]} {}
|
|
}
|