mirror of https://github.com/llvm/circt.git
[FIRRTL][InferResets] Generalize FART to support sync reset (#7476)
The FullAsyncResetAnnotation is deprecated and replaced by FullResetAnnotation which includes a resetType argument that must be 'sync' or 'async'. IgnoreFullAsyncResetAnnotation is deprecated and replaced by ExcludeFromFullResetAnnotation. The new annotations are in package circt. The behavior of FullResetAnnotation with resetType == 'async' is identical to that of the old FullAsyncResetAnnotation. The behavior of FullResetAnnotation with resetType == 'sync' is very similar, except the type of the reset wired through will be UInt<1>, and any registers with an existing reset at all (both sync or async) will be left unchanged (resetType == 'async' will add async resets to registers with existing sync resets).
This commit is contained in:
parent
2f869728d5
commit
fa95071921
|
@ -474,8 +474,55 @@ Example:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### FullResetAnnotation
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| ---------- | ------ | ------------- |
|
||||||
|
| class | string | `circt.FullAsyncResetAnnotation` |
|
||||||
|
| target | string | Reference target |
|
||||||
|
| resetType | string | "async" or "sync" |
|
||||||
|
|
||||||
|
|
||||||
|
The target must be a signal that is a reset. The type of the signal must be (or inferred
|
||||||
|
to be) the same as the reset type specified in the annotation.
|
||||||
|
|
||||||
|
Indicates that all reset-less registers which are children of the module containing
|
||||||
|
the target will have the reset targeted attached, with a reset value of 0.
|
||||||
|
|
||||||
|
The module containing the target of this annotation is not allowed to reside in multiple
|
||||||
|
hierarchies.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"class": "circt.FullResetAnnotation",
|
||||||
|
"target": "~Foo|Bar/d:Baz>reset",
|
||||||
|
"resetType": "async"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ExcludeFromFullResetAnnotation
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| ---------- | ------ | ------------- |
|
||||||
|
| class | string | `circt.ExcludeFromFullResetAnnotation` |
|
||||||
|
| target | string | Reference target |
|
||||||
|
|
||||||
|
This annotation indicates that the target moudle should be excluded from the
|
||||||
|
FullResetAnnotation of a parent module.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"class": "circt.IgnoreFullAsyncResetAnnotation",
|
||||||
|
"target": "~Foo|Bar/d:Baz"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### FullAsyncResetAnnotation
|
### FullAsyncResetAnnotation
|
||||||
|
|
||||||
|
**Deprecated, use FullResetAnnotation**
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ---------- | ------ | ------------- |
|
| ---------- | ------ | ------------- |
|
||||||
| class | string | `sifive.enterprise.firrtl.FullAsyncResetAnnotation` |
|
| class | string | `sifive.enterprise.firrtl.FullAsyncResetAnnotation` |
|
||||||
|
@ -500,6 +547,8 @@ Example:
|
||||||
|
|
||||||
### IgnoreFullAsyncResetAnnotation
|
### IgnoreFullAsyncResetAnnotation
|
||||||
|
|
||||||
|
**Deprecated, use ExcludeFromFullResetAnnotation**
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ---------- | ------ | ------------- |
|
| ---------- | ------ | ------------- |
|
||||||
| class | string | `sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation` |
|
| class | string | `sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation` |
|
||||||
|
|
|
@ -159,6 +159,11 @@ constexpr const char *elaborationArtefactsDirectoryAnnoClass =
|
||||||
constexpr const char *testHarnessPathAnnoClass =
|
constexpr const char *testHarnessPathAnnoClass =
|
||||||
"sifive.enterprise.firrtl.TestHarnessPathAnnotation";
|
"sifive.enterprise.firrtl.TestHarnessPathAnnotation";
|
||||||
/// Annotation that marks a reset (port or wire) and domain.
|
/// Annotation that marks a reset (port or wire) and domain.
|
||||||
|
constexpr const char *fullResetAnnoClass = "circt.FullResetAnnotation";
|
||||||
|
/// Annotation that marks a module as not belonging to any reset domain.
|
||||||
|
constexpr const char *excludeFromFullResetAnnoClass =
|
||||||
|
"circt.ExcludeFromFullResetAnnotation";
|
||||||
|
/// Annotation that marks a reset (port or wire) and domain.
|
||||||
constexpr const char *fullAsyncResetAnnoClass =
|
constexpr const char *fullAsyncResetAnnoClass =
|
||||||
"sifive.enterprise.firrtl.FullAsyncResetAnnotation";
|
"sifive.enterprise.firrtl.FullAsyncResetAnnotation";
|
||||||
/// Annotation that marks a module as not belonging to any reset domain.
|
/// Annotation that marks a module as not belonging to any reset domain.
|
||||||
|
|
|
@ -397,11 +397,13 @@ def InferResets : Pass<"firrtl-infer-resets", "firrtl::CircuitOp"> {
|
||||||
let summary = "Infer reset synchronicity and add implicit resets";
|
let summary = "Infer reset synchronicity and add implicit resets";
|
||||||
let description = [{
|
let description = [{
|
||||||
This pass infers whether resets are synchronous or asynchronous, and extends
|
This pass infers whether resets are synchronous or asynchronous, and extends
|
||||||
reset-less registers with an asynchronous reset based on the following
|
reset-less registers with a reset based on the following
|
||||||
annotations:
|
annotations:
|
||||||
|
|
||||||
- `sifive.enterprise.firrtl.FullAsyncResetAnnotation`
|
- `circt.FullResetAnnotation`
|
||||||
- `sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation`
|
- `circt.ExcludeFromFullResetAnnotation`
|
||||||
|
- `sifive.enterprise.firrtl.FullAsyncResetAnnotation` (deprecated)
|
||||||
|
- `sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation` (deprecated)
|
||||||
}];
|
}];
|
||||||
let constructor = "circt::firrtl::createInferResetsPass()";
|
let constructor = "circt::firrtl::createInferResetsPass()";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//===- InferResets.cpp - Infer resets and add async reset -------*- C++ -*-===//
|
//===- InferResets.cpp - Infer resets and add full reset --------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
@ -270,6 +270,15 @@ using ResetNetwork = llvm::iterator_range<
|
||||||
/// Whether a reset is sync or async.
|
/// Whether a reset is sync or async.
|
||||||
enum class ResetKind { Async, Sync };
|
enum class ResetKind { Async, Sync };
|
||||||
|
|
||||||
|
static StringRef resetKindToStringRef(const ResetKind &kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case ResetKind::Async:
|
||||||
|
return "async";
|
||||||
|
case ResetKind::Sync:
|
||||||
|
return "sync";
|
||||||
|
}
|
||||||
|
llvm_unreachable("unhandled reset kind");
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -306,12 +315,11 @@ static T &operator<<(T &os, const ResetKind &kind) {
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// Infer concrete reset types and insert full async reset.
|
/// Infer concrete reset types and insert full reset.
|
||||||
///
|
///
|
||||||
/// This pass replaces `reset` types in the IR with a concrete `asyncreset` or
|
/// This pass replaces `reset` types in the IR with a concrete `asyncreset` or
|
||||||
/// `uint<1>` depending on how the reset is used, and adds async resets to
|
/// `uint<1>` depending on how the reset is used, and adds resets to registers
|
||||||
/// registers in modules marked with the corresponding
|
/// in modules marked with the corresponding `FullResetAnnotation`.
|
||||||
/// `FullAsyncResetAnnotation`.
|
|
||||||
///
|
///
|
||||||
/// On a high level, the first stage of the pass that deals with reset inference
|
/// On a high level, the first stage of the pass that deals with reset inference
|
||||||
/// operates as follows:
|
/// operates as follows:
|
||||||
|
@ -332,28 +340,27 @@ namespace {
|
||||||
/// found in step 2. This will replace all `reset` types in the IR with
|
/// found in step 2. This will replace all `reset` types in the IR with
|
||||||
/// a concrete type.
|
/// a concrete type.
|
||||||
///
|
///
|
||||||
/// The second stage that deals with the addition of async resets operates as
|
/// The second stage that deals with the addition of full resets operates as
|
||||||
/// follows:
|
/// follows:
|
||||||
///
|
///
|
||||||
/// 4. Visit every module in the design and determine if it has an explicit
|
/// 4. Visit every module in the design and determine if it has an explicit
|
||||||
/// reset annotated. Ports of and wires in the module can have a
|
/// reset annotated. Ports of and wires in the module can have a
|
||||||
/// `FullAsyncResetAnnotation`, which marks that port or wire as the async
|
/// `FullResetAnnotation`, which marks that port or wire as the reset for
|
||||||
/// reset for the module. A module may also carry a
|
/// the module. A module may also carry a `ExcludeFromFullResetAnnotation`,
|
||||||
/// `IgnoreFullAsyncResetAnnotation`, which marks it as being explicitly not
|
/// which marks it as being explicitly not in a reset domain. These
|
||||||
/// in a reset domain. These annotations are sparse; it is very much possible
|
/// annotations are sparse; it is very much possible that just the top-level
|
||||||
/// that just the top-level module in the design has a full async reset
|
/// module in the design has a full reset annotation. A module can only
|
||||||
/// annotation. A module can only ever carry one of these annotations, which
|
/// ever carry one of these annotations, which puts it into one of three
|
||||||
/// puts it into one of three categories from an async reset inference
|
/// categories from a full reset inference perspective:
|
||||||
/// perspective:
|
|
||||||
///
|
///
|
||||||
/// a. unambiguously marks a port or wire as the module's async reset
|
/// a. unambiguously marks a port or wire as the module's full reset
|
||||||
/// b. explicitly marks it as not to have any async resets added
|
/// b. explicitly marks it as not to have any full resets added
|
||||||
/// c. inherit reset
|
/// c. inherit reset
|
||||||
///
|
///
|
||||||
/// 5. For every module in the design, determine the full async reset domain it
|
/// 5. For every module in the design, determine the full full reset domain it
|
||||||
/// is in. Note that this very narrowly deals with the inference of a
|
/// is in. Note that this very narrowly deals with the inference of a
|
||||||
/// "default" async reset, which basically goes through the IR and attaches
|
/// "default" full reset, which basically goes through the IR and attaches
|
||||||
/// all non-reset registers to a default async reset signal. If a module
|
/// all non-reset registers to a default full reset signal. If a module
|
||||||
/// carries one of the annotations mentioned in (4), the annotated port or
|
/// carries one of the annotations mentioned in (4), the annotated port or
|
||||||
/// wire is used as its reset domain. Otherwise, it inherits the reset domain
|
/// wire is used as its reset domain. Otherwise, it inherits the reset domain
|
||||||
/// from parent modules. This conceptually involves looking at all the places
|
/// from parent modules. This conceptually involves looking at all the places
|
||||||
|
@ -365,7 +372,7 @@ namespace {
|
||||||
/// its local ports or wires, or a port or wire within one of its parent
|
/// its local ports or wires, or a port or wire within one of its parent
|
||||||
/// modules.
|
/// modules.
|
||||||
///
|
///
|
||||||
/// 6. For every module in the design, determine how async resets shall be
|
/// 6. For every module in the design, determine how full resets shall be
|
||||||
/// implemented. This step handles the following distinct cases:
|
/// implemented. This step handles the following distinct cases:
|
||||||
///
|
///
|
||||||
/// a. Skip a module because it is marked as having no reset domain.
|
/// a. Skip a module because it is marked as having no reset domain.
|
||||||
|
@ -382,30 +389,30 @@ namespace {
|
||||||
/// value to reuse (port or wire), the index of an existing port to reuse,
|
/// value to reuse (port or wire), the index of an existing port to reuse,
|
||||||
/// and the name of an additional port to insert into its port list.
|
/// and the name of an additional port to insert into its port list.
|
||||||
///
|
///
|
||||||
/// 7. For every module in the design, async resets are implemented. This
|
/// 7. For every module in the design, full resets are implemented. This
|
||||||
/// determines the local value to use as the reset signal and updates the
|
/// determines the local value to use as the reset signal and updates the
|
||||||
/// `reg` and `regreset` operations in the design. If the register already
|
/// `reg` and `regreset` operations in the design. If the register already
|
||||||
/// has an async reset, it is left unchanged. If it has a sync reset, the
|
/// has an async reset, or if the type of the full reset is sync, the
|
||||||
/// sync reset is moved into a `mux` operation on all `connect`s to the
|
/// register's reset is left unchanged. If it has a sync reset and the full
|
||||||
/// register (which the Scala code base called the `RemoveResets` pass).
|
/// reset is async, the sync reset is moved into a `mux` operation on all
|
||||||
/// Finally the register is replaced with a `regreset` operation, with the
|
/// `connect`s to the register (which the Scala code base called the
|
||||||
/// reset signal determined earlier, and a "zero" value constructed for the
|
/// `RemoveResets` pass). Finally the register is replaced with a `regreset`
|
||||||
/// register's type.
|
/// operation, with the reset signal determined earlier, and a "zero" value
|
||||||
|
/// constructed for the register's type.
|
||||||
///
|
///
|
||||||
/// Determining the local reset value is trivial if step 6 found a module to
|
/// Determining the local reset value is trivial if step 6 found a module to
|
||||||
/// be of case a or b. Case c is the non-trivial one, because it requires
|
/// be of case a or b. Case c is the non-trivial one, because it requires
|
||||||
/// modifying the port list of the module. This is done by first determining
|
/// modifying the port list of the module. This is done by first determining
|
||||||
/// the name of the reset signal in the parent module, which is either the
|
/// the name of the reset signal in the parent module, which is either the
|
||||||
/// name of the port or wire declaration. We then look for an existing
|
/// name of the port or wire declaration. We then look for an existing
|
||||||
/// `asyncreset` port in the port list and reuse that as reset. If no port
|
/// port of the same type in the port list and reuse that as reset. If no
|
||||||
/// with that name was found, or the existing port is of the wrong type, a
|
/// port with that name was found, or the existing port is of the wrong type,
|
||||||
/// new port is inserted into the port list.
|
/// a new port is inserted into the port list.
|
||||||
///
|
///
|
||||||
/// TODO: This logic is *very* brittle and error-prone. It may make sense to
|
/// TODO: This logic is *very* brittle and error-prone. It may make sense to
|
||||||
/// just add an additional port for the inferred async reset in any case,
|
/// just add an additional port for the inferred reset in any case, with an
|
||||||
/// with an optimization to use an existing `asyncreset` port if all of the
|
/// optimization to use an existing port if all of the module's
|
||||||
/// module's instantiations have that port connected to the desired signal
|
/// instantiations have that port connected to the desired signal already.
|
||||||
/// already.
|
|
||||||
///
|
///
|
||||||
struct InferResetsPass
|
struct InferResetsPass
|
||||||
: public circt::firrtl::impl::InferResetsBase<InferResetsPass> {
|
: public circt::firrtl::impl::InferResetsBase<InferResetsPass> {
|
||||||
|
@ -432,12 +439,12 @@ struct InferResetsPass
|
||||||
bool updateReset(FieldRef field, FIRRTLBaseType resetType);
|
bool updateReset(FieldRef field, FIRRTLBaseType resetType);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Async reset implementation
|
// Full reset implementation
|
||||||
|
|
||||||
LogicalResult collectAnnos(CircuitOp circuit);
|
LogicalResult collectAnnos(CircuitOp circuit);
|
||||||
// Collect async reset annotations in the module and return a reset signal.
|
// Collect reset annotations in the module and return a reset signal.
|
||||||
// Return `failure()` if there was an error in the annotation processing.
|
// Return `failure()` if there was an error in the annotation processing.
|
||||||
// Return `std::nullopt` if there was no async reset annotation.
|
// Return `std::nullopt` if there was no reset annotation.
|
||||||
// Return `nullptr` if there was `ignore` annotation.
|
// Return `nullptr` if there was `ignore` annotation.
|
||||||
// Return a non-null Value if the reset was actually provided.
|
// Return a non-null Value if the reset was actually provided.
|
||||||
FailureOr<std::optional<Value>> collectAnnos(FModuleOp module);
|
FailureOr<std::optional<Value>> collectAnnos(FModuleOp module);
|
||||||
|
@ -450,9 +457,9 @@ struct InferResetsPass
|
||||||
void determineImpl();
|
void determineImpl();
|
||||||
void determineImpl(FModuleOp module, ResetDomain &domain);
|
void determineImpl(FModuleOp module, ResetDomain &domain);
|
||||||
|
|
||||||
LogicalResult implementAsyncReset();
|
LogicalResult implementFullReset();
|
||||||
LogicalResult implementAsyncReset(FModuleOp module, ResetDomain &domain);
|
LogicalResult implementFullReset(FModuleOp module, ResetDomain &domain);
|
||||||
void implementAsyncReset(Operation *op, FModuleOp module, Value actualReset);
|
void implementFullReset(Operation *op, FModuleOp module, Value actualReset);
|
||||||
|
|
||||||
LogicalResult verifyNoAbstractReset();
|
LogicalResult verifyNoAbstractReset();
|
||||||
|
|
||||||
|
@ -536,8 +543,8 @@ void InferResetsPass::runOnOperationInner() {
|
||||||
// Determine how each reset shall be implemented.
|
// Determine how each reset shall be implemented.
|
||||||
determineImpl();
|
determineImpl();
|
||||||
|
|
||||||
// Implement the async resets.
|
// Implement the full resets.
|
||||||
if (failed(implementAsyncReset()))
|
if (failed(implementFullReset()))
|
||||||
return signalPassFailure();
|
return signalPassFailure();
|
||||||
|
|
||||||
// Require that no Abstract Resets exist on ports in the design.
|
// Require that no Abstract Resets exist on ports in the design.
|
||||||
|
@ -1262,7 +1269,7 @@ bool InferResetsPass::updateReset(FieldRef field, FIRRTLBaseType resetType) {
|
||||||
LogicalResult InferResetsPass::collectAnnos(CircuitOp circuit) {
|
LogicalResult InferResetsPass::collectAnnos(CircuitOp circuit) {
|
||||||
LLVM_DEBUG({
|
LLVM_DEBUG({
|
||||||
llvm::dbgs() << "\n";
|
llvm::dbgs() << "\n";
|
||||||
debugHeader("Gather async reset annotations") << "\n\n";
|
debugHeader("Gather reset annotations") << "\n\n";
|
||||||
});
|
});
|
||||||
SmallVector<std::pair<FModuleOp, std::optional<Value>>> results;
|
SmallVector<std::pair<FModuleOp, std::optional<Value>>> results;
|
||||||
for (auto module : circuit.getOps<FModuleOp>())
|
for (auto module : circuit.getOps<FModuleOp>())
|
||||||
|
@ -1293,15 +1300,15 @@ InferResetsPass::collectAnnos(FModuleOp module) {
|
||||||
// explicitly assigns it no reset domain.
|
// explicitly assigns it no reset domain.
|
||||||
bool ignore = false;
|
bool ignore = false;
|
||||||
AnnotationSet::removeAnnotations(module, [&](Annotation anno) {
|
AnnotationSet::removeAnnotations(module, [&](Annotation anno) {
|
||||||
if (anno.isClass(ignoreFullAsyncResetAnnoClass)) {
|
if (anno.isClass(excludeFromFullResetAnnoClass)) {
|
||||||
ignore = true;
|
ignore = true;
|
||||||
conflictingAnnos.insert({anno, module.getLoc()});
|
conflictingAnnos.insert({anno, module.getLoc()});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (anno.isClass(fullAsyncResetAnnoClass)) {
|
if (anno.isClass(fullResetAnnoClass)) {
|
||||||
anyFailed = true;
|
anyFailed = true;
|
||||||
module.emitError("'FullAsyncResetAnnotation' cannot target module; "
|
module.emitError("''FullResetAnnotation' cannot target module; must "
|
||||||
"must target port or wire/node instead");
|
"target port or wire/node instead");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1311,30 +1318,65 @@ InferResetsPass::collectAnnos(FModuleOp module) {
|
||||||
|
|
||||||
// Consume any reset annotations on module ports.
|
// Consume any reset annotations on module ports.
|
||||||
Value reset;
|
Value reset;
|
||||||
AnnotationSet::removePortAnnotations(module, [&](unsigned argNum,
|
// Helper for checking annotations and determining the reset
|
||||||
Annotation anno) {
|
auto checkAnnotations = [&](Annotation anno, Value arg) {
|
||||||
Value arg = module.getArgument(argNum);
|
if (anno.isClass(fullResetAnnoClass)) {
|
||||||
if (anno.isClass(fullAsyncResetAnnoClass)) {
|
ResetKind expectedResetKind;
|
||||||
if (!isa<AsyncResetType>(arg.getType())) {
|
if (auto rt = anno.getMember<StringAttr>("resetType")) {
|
||||||
mlir::emitError(arg.getLoc(), "'FullAsyncResetAnnotation' must "
|
if (rt == "sync") {
|
||||||
"target async reset, but targets ")
|
expectedResetKind = ResetKind::Sync;
|
||||||
|
} else if (rt == "async") {
|
||||||
|
expectedResetKind = ResetKind::Async;
|
||||||
|
} else {
|
||||||
|
mlir::emitError(arg.getLoc(),
|
||||||
|
"'FullResetAnnotation' requires resetType == 'sync' "
|
||||||
|
"| 'async', but got resetType == ")
|
||||||
|
<< rt;
|
||||||
|
anyFailed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mlir::emitError(arg.getLoc(),
|
||||||
|
"'FullResetAnnotation' requires resetType == "
|
||||||
|
"'sync' | 'async', but got no resetType");
|
||||||
|
anyFailed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Check that the type is well-formed
|
||||||
|
bool isAsync = expectedResetKind == ResetKind::Async;
|
||||||
|
bool validUint = false;
|
||||||
|
if (auto uintT = dyn_cast<UIntType>(arg.getType()))
|
||||||
|
validUint = uintT.getWidth() == 1;
|
||||||
|
if ((isAsync && !isa<AsyncResetType>(arg.getType())) ||
|
||||||
|
(!isAsync && !validUint)) {
|
||||||
|
auto kind = resetKindToStringRef(expectedResetKind);
|
||||||
|
mlir::emitError(arg.getLoc(),
|
||||||
|
"'FullResetAnnotation' with resetType == '")
|
||||||
|
<< kind << "' must target " << kind << " reset, but targets "
|
||||||
<< arg.getType();
|
<< arg.getType();
|
||||||
anyFailed = true;
|
anyFailed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset = arg;
|
reset = arg;
|
||||||
conflictingAnnos.insert({anno, reset.getLoc()});
|
conflictingAnnos.insert({anno, reset.getLoc()});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (anno.isClass(ignoreFullAsyncResetAnnoClass)) {
|
if (anno.isClass(excludeFromFullResetAnnoClass)) {
|
||||||
anyFailed = true;
|
anyFailed = true;
|
||||||
mlir::emitError(arg.getLoc(),
|
mlir::emitError(arg.getLoc(),
|
||||||
"'IgnoreFullAsyncResetAnnotation' cannot target port; "
|
"'ExcludeFromFullResetAnnotation' cannot "
|
||||||
"must target module instead");
|
"target port/wire/node; must target module instead");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
AnnotationSet::removePortAnnotations(module,
|
||||||
|
[&](unsigned argNum, Annotation anno) {
|
||||||
|
Value arg = module.getArgument(argNum);
|
||||||
|
return checkAnnotations(anno, arg);
|
||||||
});
|
});
|
||||||
if (anyFailed)
|
if (anyFailed)
|
||||||
return failure();
|
return failure();
|
||||||
|
@ -1343,8 +1385,8 @@ InferResetsPass::collectAnnos(FModuleOp module) {
|
||||||
module.getBody().walk([&](Operation *op) {
|
module.getBody().walk([&](Operation *op) {
|
||||||
// Reset annotations must target wire/node ops.
|
// Reset annotations must target wire/node ops.
|
||||||
if (!isa<WireOp, NodeOp>(op)) {
|
if (!isa<WireOp, NodeOp>(op)) {
|
||||||
if (AnnotationSet::hasAnnotation(op, fullAsyncResetAnnoClass,
|
if (AnnotationSet::hasAnnotation(op, fullResetAnnoClass,
|
||||||
ignoreFullAsyncResetAnnoClass)) {
|
excludeFromFullResetAnnoClass)) {
|
||||||
anyFailed = true;
|
anyFailed = true;
|
||||||
op->emitError(
|
op->emitError(
|
||||||
"reset annotations must target module, port, or wire/node");
|
"reset annotations must target module, port, or wire/node");
|
||||||
|
@ -1355,27 +1397,8 @@ InferResetsPass::collectAnnos(FModuleOp module) {
|
||||||
// At this point we know that we have a WireOp/NodeOp. Process the reset
|
// At this point we know that we have a WireOp/NodeOp. Process the reset
|
||||||
// annotations.
|
// annotations.
|
||||||
AnnotationSet::removeAnnotations(op, [&](Annotation anno) {
|
AnnotationSet::removeAnnotations(op, [&](Annotation anno) {
|
||||||
if (anno.isClass(fullAsyncResetAnnoClass)) {
|
auto arg = op->getResult(0);
|
||||||
auto resultType = op->getResult(0).getType();
|
return checkAnnotations(anno, arg);
|
||||||
if (!isa<AsyncResetType>(resultType)) {
|
|
||||||
mlir::emitError(op->getLoc(), "'FullAsyncResetAnnotation' must "
|
|
||||||
"target async reset, but targets ")
|
|
||||||
<< resultType;
|
|
||||||
anyFailed = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
reset = op->getResult(0);
|
|
||||||
conflictingAnnos.insert({anno, reset.getLoc()});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (anno.isClass(ignoreFullAsyncResetAnnoClass)) {
|
|
||||||
anyFailed = true;
|
|
||||||
op->emitError(
|
|
||||||
"'IgnoreFullAsyncResetAnnotation' cannot target wire/node; must "
|
|
||||||
"target module instead");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (anyFailed)
|
if (anyFailed)
|
||||||
|
@ -1430,7 +1453,7 @@ InferResetsPass::collectAnnos(FModuleOp module) {
|
||||||
LogicalResult InferResetsPass::buildDomains(CircuitOp circuit) {
|
LogicalResult InferResetsPass::buildDomains(CircuitOp circuit) {
|
||||||
LLVM_DEBUG({
|
LLVM_DEBUG({
|
||||||
llvm::dbgs() << "\n";
|
llvm::dbgs() << "\n";
|
||||||
debugHeader("Build async reset domains") << "\n\n";
|
debugHeader("Build full reset domains") << "\n\n";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gather the domains.
|
// Gather the domains.
|
||||||
|
@ -1559,7 +1582,7 @@ void InferResetsPass::determineImpl() {
|
||||||
/// - If the domain is the place where the reset is defined ("top"), fills in
|
/// - If the domain is the place where the reset is defined ("top"), fills in
|
||||||
/// the existing port/wire/node as reset.
|
/// the existing port/wire/node as reset.
|
||||||
/// - If the module already has a port with the reset's name:
|
/// - If the module already has a port with the reset's name:
|
||||||
/// - If the type is `asyncreset`, reuses that port.
|
/// - If the port has the same type as the reset domain, reuses that port.
|
||||||
/// - Otherwise appends a `_N` suffix with increasing N to create a
|
/// - Otherwise appends a `_N` suffix with increasing N to create a
|
||||||
/// yet-unused
|
/// yet-unused
|
||||||
/// port name, and marks that as to be created.
|
/// port name, and marks that as to be created.
|
||||||
|
@ -1629,17 +1652,17 @@ void InferResetsPass::determineImpl(FModuleOp module, ResetDomain &domain) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Async Reset Implementation
|
// Full Reset Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Implement the async resets gathered in the pass' `domains` map.
|
/// Implement the annotated resets gathered in the pass' `domains` map.
|
||||||
LogicalResult InferResetsPass::implementAsyncReset() {
|
LogicalResult InferResetsPass::implementFullReset() {
|
||||||
LLVM_DEBUG({
|
LLVM_DEBUG({
|
||||||
llvm::dbgs() << "\n";
|
llvm::dbgs() << "\n";
|
||||||
debugHeader("Implement async resets") << "\n\n";
|
debugHeader("Implement full resets") << "\n\n";
|
||||||
});
|
});
|
||||||
for (auto &it : domains)
|
for (auto &it : domains)
|
||||||
if (failed(implementAsyncReset(cast<FModuleOp>(it.first),
|
if (failed(implementFullReset(cast<FModuleOp>(it.first),
|
||||||
it.second.back().first)))
|
it.second.back().first)))
|
||||||
return failure();
|
return failure();
|
||||||
return success();
|
return success();
|
||||||
|
@ -1650,9 +1673,9 @@ LogicalResult InferResetsPass::implementAsyncReset() {
|
||||||
/// This will add ports to the module as appropriate, update the register ops
|
/// This will add ports to the module as appropriate, update the register ops
|
||||||
/// in the module, and update any instantiated submodules with their
|
/// in the module, and update any instantiated submodules with their
|
||||||
/// corresponding reset implementation details.
|
/// corresponding reset implementation details.
|
||||||
LogicalResult InferResetsPass::implementAsyncReset(FModuleOp module,
|
LogicalResult InferResetsPass::implementFullReset(FModuleOp module,
|
||||||
ResetDomain &domain) {
|
ResetDomain &domain) {
|
||||||
LLVM_DEBUG(llvm::dbgs() << "Implementing async reset for " << module.getName()
|
LLVM_DEBUG(llvm::dbgs() << "Implementing full reset for " << module.getName()
|
||||||
<< "\n");
|
<< "\n");
|
||||||
|
|
||||||
// Nothing to do if the module was marked explicitly with no reset domain.
|
// Nothing to do if the module was marked explicitly with no reset domain.
|
||||||
|
@ -1666,7 +1689,7 @@ LogicalResult InferResetsPass::implementAsyncReset(FModuleOp module,
|
||||||
Value actualReset = domain.existingValue;
|
Value actualReset = domain.existingValue;
|
||||||
if (domain.newPortName) {
|
if (domain.newPortName) {
|
||||||
PortInfo portInfo{domain.newPortName,
|
PortInfo portInfo{domain.newPortName,
|
||||||
AsyncResetType::get(&getContext()),
|
domain.reset.getType(),
|
||||||
Direction::In,
|
Direction::In,
|
||||||
{},
|
{},
|
||||||
domain.reset.getLoc()};
|
domain.reset.getLoc()};
|
||||||
|
@ -1771,14 +1794,14 @@ LogicalResult InferResetsPass::implementAsyncReset(FModuleOp module,
|
||||||
|
|
||||||
// Update the operations.
|
// Update the operations.
|
||||||
for (auto *op : opsToUpdate)
|
for (auto *op : opsToUpdate)
|
||||||
implementAsyncReset(op, module, actualReset);
|
implementFullReset(op, module, actualReset);
|
||||||
|
|
||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify an operation in a module to implement an async reset for that
|
/// Modify an operation in a module to implement an full reset for that
|
||||||
/// module.
|
/// module.
|
||||||
void InferResetsPass::implementAsyncReset(Operation *op, FModuleOp module,
|
void InferResetsPass::implementFullReset(Operation *op, FModuleOp module,
|
||||||
Value actualReset) {
|
Value actualReset) {
|
||||||
ImplicitLocOpBuilder builder(op->getLoc(), op);
|
ImplicitLocOpBuilder builder(op->getLoc(), op);
|
||||||
|
|
||||||
|
@ -1840,7 +1863,7 @@ void InferResetsPass::implementAsyncReset(Operation *op, FModuleOp module,
|
||||||
if (AnnotationSet::removeAnnotations(regOp, excludeMemToRegAnnoClass))
|
if (AnnotationSet::removeAnnotations(regOp, excludeMemToRegAnnoClass))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LLVM_DEBUG(llvm::dbgs() << "- Adding async reset to " << regOp << "\n");
|
LLVM_DEBUG(llvm::dbgs() << "- Adding full reset to " << regOp << "\n");
|
||||||
auto zero = createZeroValue(builder, regOp.getResult().getType());
|
auto zero = createZeroValue(builder, regOp.getResult().getType());
|
||||||
auto newRegOp = builder.create<RegResetOp>(
|
auto newRegOp = builder.create<RegResetOp>(
|
||||||
regOp.getResult().getType(), regOp.getClockVal(), actualReset, zero,
|
regOp.getResult().getType(), regOp.getClockVal(), actualReset, zero,
|
||||||
|
@ -1855,10 +1878,11 @@ void InferResetsPass::implementAsyncReset(Operation *op, FModuleOp module,
|
||||||
|
|
||||||
// Handle registers with reset.
|
// Handle registers with reset.
|
||||||
if (auto regOp = dyn_cast<RegResetOp>(op)) {
|
if (auto regOp = dyn_cast<RegResetOp>(op)) {
|
||||||
// If the register already has an async reset, leave it untouched.
|
// If the register already has an async reset or if the type of the added
|
||||||
if (type_isa<AsyncResetType>(regOp.getResetSignal().getType())) {
|
// reset is sync, leave it alone.
|
||||||
LLVM_DEBUG(llvm::dbgs()
|
if (type_isa<AsyncResetType>(regOp.getResetSignal().getType()) ||
|
||||||
<< "- Skipping (has async reset) " << regOp << "\n");
|
type_isa<UIntType>(actualReset.getType())) {
|
||||||
|
LLVM_DEBUG(llvm::dbgs() << "- Skipping (has reset) " << regOp << "\n");
|
||||||
// The following performs the logic of `CheckResets` in the original
|
// The following performs the logic of `CheckResets` in the original
|
||||||
// Scala source code.
|
// Scala source code.
|
||||||
if (failed(regOp.verifyInvariants()))
|
if (failed(regOp.verifyInvariants()))
|
||||||
|
@ -1870,9 +1894,9 @@ void InferResetsPass::implementAsyncReset(Operation *op, FModuleOp module,
|
||||||
auto reset = regOp.getResetSignal();
|
auto reset = regOp.getResetSignal();
|
||||||
auto value = regOp.getResetValue();
|
auto value = regOp.getResetValue();
|
||||||
|
|
||||||
// If we arrive here, the register has a sync reset. In order to add an
|
// If we arrive here, the register has a sync reset and the added reset is
|
||||||
// async reset, we have to move the sync reset into a mux in front of the
|
// async. In order to add an async reset, we have to move the sync reset
|
||||||
// register.
|
// into a mux in front of the register.
|
||||||
insertResetMux(builder, regOp.getResult(), reset, value);
|
insertResetMux(builder, regOp.getResult(), reset, value);
|
||||||
builder.setInsertionPointAfterValue(regOp.getResult());
|
builder.setInsertionPointAfterValue(regOp.getResult());
|
||||||
auto mux = builder.create<MuxPrimOp>(reset, value, regOp.getResult());
|
auto mux = builder.create<MuxPrimOp>(reset, value, regOp.getResult());
|
||||||
|
|
|
@ -435,6 +435,45 @@ static LogicalResult applyOutputDirAnno(const AnnoPathValue &target,
|
||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert from FullAsyncResetAnnotation to FullResetAnnotation
|
||||||
|
static LogicalResult convertToFullResetAnnotation(const AnnoPathValue &target,
|
||||||
|
DictionaryAttr anno,
|
||||||
|
ApplyState &state) {
|
||||||
|
auto *op = target.ref.getOp();
|
||||||
|
auto *context = op->getContext();
|
||||||
|
|
||||||
|
mlir::emitWarning(op->getLoc())
|
||||||
|
<< "'" << fullAsyncResetAnnoClass << "' is deprecated, use '"
|
||||||
|
<< fullResetAnnoClass << "' instead";
|
||||||
|
|
||||||
|
NamedAttrList newAnno(anno.getValue());
|
||||||
|
newAnno.set("class", StringAttr::get(context, fullResetAnnoClass));
|
||||||
|
newAnno.append("resetType", StringAttr::get(context, "async"));
|
||||||
|
|
||||||
|
DictionaryAttr newDictionary = DictionaryAttr::get(op->getContext(), newAnno);
|
||||||
|
|
||||||
|
return applyWithoutTarget<false>(target, newDictionary, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from IgnoreFullAsyncResetAnnotation to
|
||||||
|
/// ExcludeFromFullResetAnnotation
|
||||||
|
static LogicalResult convertToExcludeFromFullResetAnnotation(
|
||||||
|
const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state) {
|
||||||
|
auto *op = target.ref.getOp();
|
||||||
|
auto *context = op->getContext();
|
||||||
|
|
||||||
|
mlir::emitWarning(op->getLoc())
|
||||||
|
<< "'" << ignoreFullAsyncResetAnnoClass << "' is deprecated, use '"
|
||||||
|
<< excludeFromFullResetAnnoClass << "' instead";
|
||||||
|
|
||||||
|
NamedAttrList newAnno(anno.getValue());
|
||||||
|
newAnno.set("class", StringAttr::get(context, excludeFromFullResetAnnoClass));
|
||||||
|
|
||||||
|
DictionaryAttr newDictionary = DictionaryAttr::get(op->getContext(), newAnno);
|
||||||
|
|
||||||
|
return applyWithoutTarget<true, FModuleOp>(target, newDictionary, state);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Driving table
|
// Driving table
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -543,9 +582,12 @@ static llvm::StringMap<AnnoRecord> annotationRecords{{
|
||||||
{addSeqMemPortsFileAnnoClass, NoTargetAnnotation},
|
{addSeqMemPortsFileAnnoClass, NoTargetAnnotation},
|
||||||
{extractClockGatesAnnoClass, NoTargetAnnotation},
|
{extractClockGatesAnnoClass, NoTargetAnnotation},
|
||||||
{extractBlackBoxAnnoClass, {stdResolve, applyWithoutTarget<false>}},
|
{extractBlackBoxAnnoClass, {stdResolve, applyWithoutTarget<false>}},
|
||||||
{fullAsyncResetAnnoClass, {stdResolve, applyWithoutTarget<false>}},
|
{fullResetAnnoClass, {stdResolve, applyWithoutTarget<false>}},
|
||||||
{ignoreFullAsyncResetAnnoClass,
|
{excludeFromFullResetAnnoClass,
|
||||||
{stdResolve, applyWithoutTarget<true, FModuleOp>}},
|
{stdResolve, applyWithoutTarget<true, FModuleOp>}},
|
||||||
|
{fullAsyncResetAnnoClass, {stdResolve, convertToFullResetAnnotation}},
|
||||||
|
{ignoreFullAsyncResetAnnoClass,
|
||||||
|
{stdResolve, convertToExcludeFromFullResetAnnotation}},
|
||||||
{decodeTableAnnotation, {noResolve, drop}},
|
{decodeTableAnnotation, {noResolve, drop}},
|
||||||
{blackBoxTargetDirAnnoClass, NoTargetAnnotation},
|
{blackBoxTargetDirAnnoClass, NoTargetAnnotation},
|
||||||
{traceNameAnnoClass, {stdResolve, applyTraceName}},
|
{traceNameAnnoClass, {stdResolve, applyTraceName}},
|
||||||
|
|
|
@ -54,21 +54,18 @@ void SFCCompatPass::runOnOperation() {
|
||||||
bool madeModifications = false;
|
bool madeModifications = false;
|
||||||
SmallVector<InvalidValueOp> invalidOps;
|
SmallVector<InvalidValueOp> invalidOps;
|
||||||
|
|
||||||
auto fullAsyncResetAttr =
|
auto fullResetAttr = StringAttr::get(&getContext(), fullResetAnnoClass);
|
||||||
StringAttr::get(&getContext(), fullAsyncResetAnnoClass);
|
auto isFullResetAnno = [fullResetAttr](Annotation anno) {
|
||||||
auto isFullAsyncResetAnno = [fullAsyncResetAttr](Annotation anno) {
|
auto annoClassAttr = anno.getClassAttr();
|
||||||
return anno.getClassAttr() == fullAsyncResetAttr;
|
return annoClassAttr == fullResetAttr;
|
||||||
};
|
};
|
||||||
bool fullAsyncResetExists = AnnotationSet::removePortAnnotations(
|
bool fullResetExists = AnnotationSet::removePortAnnotations(
|
||||||
getOperation(), [&](unsigned argNum, Annotation anno) {
|
getOperation(),
|
||||||
return isFullAsyncResetAnno(anno);
|
[&](unsigned argNum, Annotation anno) { return isFullResetAnno(anno); });
|
||||||
|
getOperation()->walk([isFullResetAnno, &fullResetExists](Operation *op) {
|
||||||
|
fullResetExists |= AnnotationSet::removeAnnotations(op, isFullResetAnno);
|
||||||
});
|
});
|
||||||
getOperation()->walk(
|
madeModifications |= fullResetExists;
|
||||||
[isFullAsyncResetAnno, &fullAsyncResetExists](Operation *op) {
|
|
||||||
fullAsyncResetExists |=
|
|
||||||
AnnotationSet::removeAnnotations(op, isFullAsyncResetAnno);
|
|
||||||
});
|
|
||||||
madeModifications |= fullAsyncResetExists;
|
|
||||||
|
|
||||||
auto result = getOperation()->walk([&](Operation *op) {
|
auto result = getOperation()->walk([&](Operation *op) {
|
||||||
// Populate invalidOps for later handling.
|
// Populate invalidOps for later handling.
|
||||||
|
@ -82,8 +79,7 @@ void SFCCompatPass::runOnOperation() {
|
||||||
|
|
||||||
// If the `RegResetOp` has an invalidated initialization and we
|
// If the `RegResetOp` has an invalidated initialization and we
|
||||||
// are not running FART, then replace it with a `RegOp`.
|
// are not running FART, then replace it with a `RegOp`.
|
||||||
if (!fullAsyncResetExists &&
|
if (!fullResetExists && walkDrivers(reg.getResetValue(), true, true, false,
|
||||||
walkDrivers(reg.getResetValue(), true, true, false,
|
|
||||||
[](FieldRef dst, FieldRef src) {
|
[](FieldRef dst, FieldRef src) {
|
||||||
return src.isa<InvalidValueOp>();
|
return src.isa<InvalidValueOp>();
|
||||||
})) {
|
})) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-annotations{allow-adding-ports-on-public-modules=true}))' --split-input-file %s | FileCheck %s
|
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-annotations{allow-adding-ports-on-public-modules=true}))' --verify-diagnostics --split-input-file %s | FileCheck %s
|
||||||
|
|
||||||
// circt.test copies the annotation to the target
|
// circt.test copies the annotation to the target
|
||||||
// circt.testNT puts the targetless annotation on the circuit
|
// circt.testNT puts the targetless annotation on the circuit
|
||||||
|
@ -1953,3 +1953,35 @@ firrtl.circuit "Top" attributes {
|
||||||
// CHECK-SAME: attributes {output_file = #hw.output_file<"foobarbaz{{/|\\\\}}qux{{/|\\\\}}">}
|
// CHECK-SAME: attributes {output_file = #hw.output_file<"foobarbaz{{/|\\\\}}qux{{/|\\\\}}">}
|
||||||
firrtl.module @Top() {}
|
firrtl.module @Top() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
// Check that FullAsyncResetAnnotation is lowered to FullResetAnnotation (and prints a warning)
|
||||||
|
// CHECK-LABEL: firrtl.circuit "Top"
|
||||||
|
firrtl.circuit "Top" attributes {
|
||||||
|
rawAnnotations = [
|
||||||
|
{
|
||||||
|
class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation",
|
||||||
|
target = "~Top|Top>reset"
|
||||||
|
}]
|
||||||
|
} {
|
||||||
|
// CHECK-LABEL: firrtl.module @Top
|
||||||
|
// CHECK-SAME: (in %reset: !firrtl.asyncreset [{class = "circt.FullResetAnnotation", resetType = "async"}])
|
||||||
|
// expected-warning @+1 {{'sifive.enterprise.firrtl.FullAsyncResetAnnotation' is deprecated, use 'circt.FullResetAnnotation' instead}}
|
||||||
|
firrtl.module @Top(in %reset: !firrtl.asyncreset) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
// Check that IgnoreFullAsyncResetAnnotation is lowered to ExcludeFromFullResetAnnotation (and prints a warning)
|
||||||
|
// CHECK-LABEL: firrtl.circuit "Top"
|
||||||
|
firrtl.circuit "Top" attributes {
|
||||||
|
rawAnnotations = [
|
||||||
|
{
|
||||||
|
class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation",
|
||||||
|
target = "~Top|Top"
|
||||||
|
}]
|
||||||
|
} {
|
||||||
|
// CHECK-LABEL: firrtl.module @Top
|
||||||
|
// CHECK-SAME: (in %reset: !firrtl.asyncreset) attributes {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]}
|
||||||
|
// expected-warning @+1 {{'sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation' is deprecated, use 'circt.ExcludeFromFullResetAnnotation' instead}}
|
||||||
|
firrtl.module @Top(in %reset: !firrtl.asyncreset) {}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
// - github.com/sifive/$internal:
|
// - github.com/sifive/$internal:
|
||||||
// - test/scala/firrtl/FullAsyncResetTransform.scala
|
// - test/scala/firrtl/FullAsyncResetTransform.scala
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Reset Inference
|
// Reset Inference
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -152,34 +151,43 @@ firrtl.circuit "top" {
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Full Async Reset
|
// Full Reset
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
// Reset annotation cannot target module
|
// Reset annotation cannot target module
|
||||||
firrtl.circuit "top" {
|
firrtl.circuit "top" {
|
||||||
// expected-error @+1 {{FullAsyncResetAnnotation' cannot target module; must target port or wire/node instead}}
|
// expected-error @+1 {{'FullResetAnnotation' cannot target module; must target port or wire/node instead}}
|
||||||
firrtl.module @top() attributes {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} {
|
firrtl.module @top() attributes {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
// Reset annotation cannot target synchronous reset signals
|
// Reset annotation resetType must match type of signal
|
||||||
firrtl.circuit "top" {
|
firrtl.circuit "top" {
|
||||||
firrtl.module @top() {
|
firrtl.module @top() {
|
||||||
// expected-error @below {{'FullAsyncResetAnnotation' must target async reset, but targets '!firrtl.uint<1>'}}
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'async' must target async reset, but targets '!firrtl.uint<1>'}}
|
||||||
%innerReset = firrtl.wire {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !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 be synchronous
|
// Reset annotation cannot target reset signals which are inferred to the wrong type
|
||||||
firrtl.circuit "top" {
|
firrtl.circuit "top" {
|
||||||
firrtl.module @top() {
|
firrtl.module @top() {
|
||||||
// expected-error @below {{'FullAsyncResetAnnotation' must target async reset, but targets '!firrtl.uint<1>'}}
|
// expected-error @below {{'FullResetAnnotation' with resetType == 'async' must target async reset, but targets '!firrtl.uint<1>'}}
|
||||||
%innerReset = firrtl.wire {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.reset
|
%innerReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.reset
|
||||||
%invalid = firrtl.invalidvalue : !firrtl.reset
|
%invalid = firrtl.invalidvalue : !firrtl.reset
|
||||||
firrtl.matchingconnect %innerReset, %invalid : !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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +195,8 @@ firrtl.circuit "top" {
|
||||||
// -----
|
// -----
|
||||||
// Ignore reset annotation cannot target port
|
// Ignore reset annotation cannot target port
|
||||||
firrtl.circuit "top" {
|
firrtl.circuit "top" {
|
||||||
// expected-error @+1 {{IgnoreFullAsyncResetAnnotation' cannot target port; must target module instead}}
|
// expected-error @+1 {{ExcludeFromFullResetAnnotation' cannot target port/wire/node; must target module instead}}
|
||||||
firrtl.module @top(in %reset: !firrtl.asyncreset) attributes {portAnnotations =[[{class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]]} {
|
firrtl.module @top(in %reset: !firrtl.asyncreset) attributes {portAnnotations =[[{class = "circt.ExcludeFromFullResetAnnotation"}]]} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,14 +204,14 @@ firrtl.circuit "top" {
|
||||||
// Ignore reset annotation cannot target wire/node
|
// Ignore reset annotation cannot target wire/node
|
||||||
firrtl.circuit "top" {
|
firrtl.circuit "top" {
|
||||||
firrtl.module @top() {
|
firrtl.module @top() {
|
||||||
// expected-error @+1 {{IgnoreFullAsyncResetAnnotation' cannot target wire/node; must target module instead}}
|
// expected-error @+1 {{ExcludeFromFullResetAnnotation' cannot target port/wire/node; must target module instead}}
|
||||||
%0 = firrtl.wire {annotations = [{class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%0 = firrtl.wire {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} : !firrtl.asyncreset
|
||||||
// expected-error @+1 {{IgnoreFullAsyncResetAnnotation' cannot target wire/node; must target module instead}}
|
// expected-error @+1 {{ExcludeFromFullResetAnnotation' cannot target port/wire/node; must target module instead}}
|
||||||
%1 = firrtl.node %0 {annotations = [{class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%1 = firrtl.node %0 {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} : !firrtl.asyncreset
|
||||||
// expected-error @+1 {{reset annotations must target module, port, or wire/node}}
|
// expected-error @+1 {{reset annotations must target module, port, or wire/node}}
|
||||||
%2 = firrtl.asUInt %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : (!firrtl.asyncreset) -> !firrtl.uint<1>
|
%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}}
|
// expected-error @+1 {{reset annotations must target module, port, or wire/node}}
|
||||||
%3 = firrtl.asUInt %0 {annotations = [{class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]} : (!firrtl.asyncreset) -> !firrtl.uint<1>
|
%3 = firrtl.asUInt %0 {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} : (!firrtl.asyncreset) -> !firrtl.uint<1>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,12 +219,12 @@ firrtl.circuit "top" {
|
||||||
// Cannot have multiple reset annotations on a module
|
// Cannot have multiple reset annotations on a module
|
||||||
firrtl.circuit "top" {
|
firrtl.circuit "top" {
|
||||||
// expected-error @+2 {{multiple reset annotations on module 'top'}}
|
// expected-error @+2 {{multiple reset annotations on module 'top'}}
|
||||||
// expected-note @+1 {{conflicting "sifive.enterprise.firrtl.FullAsyncResetAnnotation":}}
|
// expected-note @+1 {{conflicting "circt.FullResetAnnotation":}}
|
||||||
firrtl.module @top(in %outerReset: !firrtl.asyncreset) attributes {portAnnotations = [[{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
firrtl.module @top(in %outerReset: !firrtl.asyncreset) attributes {portAnnotations = [[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
||||||
// expected-note @+1 {{conflicting "sifive.enterprise.firrtl.FullAsyncResetAnnotation":}}
|
// expected-note @+1 {{conflicting "circt.FullResetAnnotation":}}
|
||||||
%innerReset = firrtl.wire {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%innerReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
// expected-note @+1 {{conflicting "sifive.enterprise.firrtl.FullAsyncResetAnnotation":}}
|
// expected-note @+1 {{conflicting "circt.FullResetAnnotation":}}
|
||||||
%anotherReset = firrtl.node %innerReset {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%anotherReset = firrtl.node %innerReset {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,18 +236,18 @@ firrtl.circuit "Top" {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
|
||||||
}
|
}
|
||||||
// expected-note @+1 {{reset domain 'otherReset' of module 'Child' declared here:}}
|
// 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 = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
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'}}
|
// 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)
|
%inst_clock = firrtl.instance inst @Foo(in clock: !firrtl.clock)
|
||||||
firrtl.connect %inst_clock, %clock : !firrtl.clock, !firrtl.clock
|
firrtl.connect %inst_clock, %clock : !firrtl.clock, !firrtl.clock
|
||||||
}
|
}
|
||||||
firrtl.module @Other(in %clock: !firrtl.clock) attributes {annotations = [{class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]} {
|
firrtl.module @Other(in %clock: !firrtl.clock) attributes {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} {
|
||||||
// expected-note @+1 {{instance 'other/inst' is in no reset domain}}
|
// expected-note @+1 {{instance 'other/inst' is in no reset domain}}
|
||||||
%inst_clock = firrtl.instance inst @Foo(in clock: !firrtl.clock)
|
%inst_clock = firrtl.instance inst @Foo(in clock: !firrtl.clock)
|
||||||
firrtl.connect %inst_clock, %clock : !firrtl.clock, !firrtl.clock
|
firrtl.connect %inst_clock, %clock : !firrtl.clock, !firrtl.clock
|
||||||
}
|
}
|
||||||
// expected-note @+1 {{reset domain 'reset' of module 'Top' declared here:}}
|
// 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 = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
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)
|
%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)
|
%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'}}
|
// expected-note @+1 {{instance 'foo' is in reset domain rooted at 'reset' of module 'Top'}}
|
||||||
|
@ -266,3 +274,10 @@ firrtl.circuit "UninferredRefReset" {
|
||||||
// expected-note @+1 {{the module with this uninferred reset port was defined here}}
|
// expected-note @+1 {{the module with this uninferred reset port was defined here}}
|
||||||
firrtl.module private @UninferredRefResetPriv(out %reset: !firrtl.probe<reset>) {}
|
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"}]]} {}
|
||||||
|
}
|
|
@ -358,18 +358,18 @@ firrtl.module @ForeignTypes(out %out: !firrtl.reset) {
|
||||||
|
|
||||||
|
|
||||||
// CHECK-LABEL: firrtl.module @ConsumeIgnoreAnno
|
// CHECK-LABEL: firrtl.module @ConsumeIgnoreAnno
|
||||||
// CHECK-NOT: IgnoreFullAsyncResetAnnotation
|
// CHECK-NOT: ExcludeFromFullResetAnnotation
|
||||||
firrtl.module @ConsumeIgnoreAnno() attributes {annotations = [{class = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]} {
|
firrtl.module @ConsumeIgnoreAnno() attributes {annotations = [{class = "circt.ExcludeFromFullResetAnnotation"}]} {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // firrtl.circuit
|
} // firrtl.circuit
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
// Reset-less registers should inherit the annotated async reset signal.
|
// AsyncReset-less registers should inherit the annotated async reset signal.
|
||||||
firrtl.circuit "Top" {
|
firrtl.circuit "Top" {
|
||||||
// CHECK-LABEL: firrtl.module @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 {
|
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 = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
||||||
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<8>
|
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<8>
|
||||||
// CHECK: %reg1 = firrtl.regreset sym @reg1 %clock, %extraReset, %c0_ui8
|
// CHECK: %reg1 = firrtl.regreset sym @reg1 %clock, %extraReset, %c0_ui8
|
||||||
%reg1 = firrtl.reg sym @reg1 %clock : !firrtl.clock, !firrtl.uint<8>
|
%reg1 = firrtl.reg sym @reg1 %clock : !firrtl.clock, !firrtl.uint<8>
|
||||||
|
@ -434,13 +434,36 @@ firrtl.circuit "Top" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
// 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
|
// Async reset inference should be able to construct reset values for aggregate
|
||||||
// types.
|
// types.
|
||||||
firrtl.circuit "Top" {
|
firrtl.circuit "Top" {
|
||||||
// CHECK-LABEL: firrtl.module @Top
|
// CHECK-LABEL: firrtl.module @Top
|
||||||
firrtl.module @Top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
|
firrtl.module @Top(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
|
||||||
portAnnotations = [[],[{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
||||||
// CHECK: %c0_ui = firrtl.constant 0 : !firrtl.const.uint
|
// CHECK: %c0_ui = firrtl.constant 0 : !firrtl.const.uint
|
||||||
// CHECK: %reg_uint = firrtl.regreset %clock, %reset, %c0_ui
|
// CHECK: %reg_uint = firrtl.regreset %clock, %reset, %c0_ui
|
||||||
%reg_uint = firrtl.reg %clock : !firrtl.clock, !firrtl.uint
|
%reg_uint = firrtl.reg %clock : !firrtl.clock, !firrtl.uint
|
||||||
|
@ -476,8 +499,8 @@ firrtl.circuit "Top" {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
// Reset should reuse ports if name and type matches.
|
// Reset should reuse ports if name and type matches for async wiring.
|
||||||
firrtl.circuit "ReusePorts" {
|
firrtl.circuit "ReusePortsAsync" {
|
||||||
// CHECK-LABEL: firrtl.module @Child
|
// CHECK-LABEL: firrtl.module @Child
|
||||||
// CHECK-SAME: in %clock: !firrtl.clock
|
// CHECK-SAME: in %clock: !firrtl.clock
|
||||||
// CHECK-SAME: in %reset: !firrtl.asyncreset
|
// CHECK-SAME: in %reset: !firrtl.asyncreset
|
||||||
|
@ -502,8 +525,8 @@ firrtl.circuit "ReusePorts" {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
|
||||||
}
|
}
|
||||||
// CHECK-LABEL: firrtl.module @ReusePorts
|
// CHECK-LABEL: firrtl.module @ReusePorts
|
||||||
firrtl.module @ReusePorts(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
|
firrtl.module @ReusePortsAsync(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
|
||||||
portAnnotations = [[],[{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
||||||
// CHECK: %child_clock, %child_reset = firrtl.instance child
|
// CHECK: %child_clock, %child_reset = firrtl.instance child
|
||||||
// CHECK: firrtl.matchingconnect %child_reset, %reset
|
// CHECK: firrtl.matchingconnect %child_reset, %reset
|
||||||
// CHECK: %badName_reset, %badName_clock, %badName_existingReset = firrtl.instance badName
|
// CHECK: %badName_reset, %badName_clock, %badName_existingReset = firrtl.instance badName
|
||||||
|
@ -516,6 +539,47 @@ firrtl.circuit "ReusePorts" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
// 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
|
// Infer async reset: nested
|
||||||
firrtl.circuit "FullAsyncNested" {
|
firrtl.circuit "FullAsyncNested" {
|
||||||
|
@ -544,7 +608,7 @@ firrtl.circuit "FullAsyncNested" {
|
||||||
}
|
}
|
||||||
// CHECK-LABEL: firrtl.module @FullAsyncNested
|
// 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 {
|
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 = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}], [], []] } {
|
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>)
|
%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_clock, %clock : !firrtl.clock
|
||||||
firrtl.matchingconnect %inst_reset, %reset : !firrtl.asyncreset
|
firrtl.matchingconnect %inst_reset, %reset : !firrtl.asyncreset
|
||||||
|
@ -560,7 +624,7 @@ firrtl.circuit "FullAsyncNested" {
|
||||||
firrtl.circuit "FullAsyncExcluded" {
|
firrtl.circuit "FullAsyncExcluded" {
|
||||||
// CHECK-LABEL: firrtl.module @FullAsyncExcludedChild
|
// 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>)
|
// 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 = "sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation"}]} {
|
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
|
// CHECK: %io_out_REG = firrtl.reg %clock
|
||||||
%io_out_REG = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8>
|
%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_REG, %io_in : !firrtl.uint<8>
|
||||||
|
@ -568,7 +632,7 @@ firrtl.circuit "FullAsyncExcluded" {
|
||||||
}
|
}
|
||||||
// CHECK-LABEL: firrtl.module @FullAsyncExcluded
|
// 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 {
|
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 = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
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
|
// 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>)
|
%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_clock, %clock : !firrtl.clock
|
||||||
|
@ -586,7 +650,7 @@ firrtl.circuit "WireShouldDominate" {
|
||||||
// CHECK-LABEL: firrtl.module @WireShouldDominate
|
// CHECK-LABEL: firrtl.module @WireShouldDominate
|
||||||
firrtl.module @WireShouldDominate(in %clock: !firrtl.clock) {
|
firrtl.module @WireShouldDominate(in %clock: !firrtl.clock) {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
||||||
%localReset = firrtl.wire {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.wire {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
// CHECK-NEXT: %localReset = firrtl.wire
|
// CHECK-NEXT: %localReset = firrtl.wire
|
||||||
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
||||||
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
|
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
|
||||||
|
@ -602,7 +666,7 @@ firrtl.circuit "MovableNodeShouldDominate" {
|
||||||
firrtl.module @MovableNodeShouldDominate(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
|
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
|
%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
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
||||||
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
// CHECK-NEXT: %0 = firrtl.asAsyncReset %ui1
|
// CHECK-NEXT: %0 = firrtl.asAsyncReset %ui1
|
||||||
// CHECK-NEXT: %localReset = firrtl.node sym @theReset %0
|
// CHECK-NEXT: %localReset = firrtl.node sym @theReset %0
|
||||||
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
||||||
|
@ -620,7 +684,7 @@ firrtl.circuit "UnmovableNodeShouldDominate" {
|
||||||
firrtl.module @UnmovableNodeShouldDominate(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
|
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
|
%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
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
||||||
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
// CHECK-NEXT: %localReset = firrtl.wire sym @theReset
|
// CHECK-NEXT: %localReset = firrtl.wire sym @theReset
|
||||||
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
||||||
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
|
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
|
||||||
|
@ -638,7 +702,7 @@ firrtl.circuit "UnmovableForceableNodeShouldDominate" {
|
||||||
firrtl.module @UnmovableForceableNodeShouldDominate(in %clock: !firrtl.clock, in %ui1: !firrtl.uint<1>) {
|
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
|
%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
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
||||||
%localReset, %ref = firrtl.node sym @theReset %0 forceable {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%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: %localReset, %{{.+}} = firrtl.wire sym @theReset
|
||||||
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
||||||
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
|
// CHECK-NEXT: %reg = firrtl.regreset %clock, %localReset, [[RV]]
|
||||||
|
@ -660,7 +724,7 @@ firrtl.circuit "MoveAcrossBlocks1" {
|
||||||
}
|
}
|
||||||
firrtl.when %ui1 : !firrtl.uint<1> {
|
firrtl.when %ui1 : !firrtl.uint<1> {
|
||||||
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
||||||
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
}
|
}
|
||||||
// CHECK-NEXT: %localReset = firrtl.wire
|
// CHECK-NEXT: %localReset = firrtl.wire
|
||||||
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
|
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
|
||||||
|
@ -683,7 +747,7 @@ firrtl.circuit "MoveAcrossBlocks2" {
|
||||||
// <-- should move reset here
|
// <-- should move reset here
|
||||||
firrtl.when %ui1 : !firrtl.uint<1> {
|
firrtl.when %ui1 : !firrtl.uint<1> {
|
||||||
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
||||||
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
}
|
}
|
||||||
firrtl.when %ui1 : !firrtl.uint<1> {
|
firrtl.when %ui1 : !firrtl.uint<1> {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
||||||
|
@ -710,7 +774,7 @@ firrtl.circuit "MoveAcrossBlocks3" {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
||||||
firrtl.when %ui1 : !firrtl.uint<1> {
|
firrtl.when %ui1 : !firrtl.uint<1> {
|
||||||
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
||||||
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
}
|
}
|
||||||
// CHECK-NEXT: %localReset = firrtl.wire
|
// CHECK-NEXT: %localReset = firrtl.wire
|
||||||
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
||||||
|
@ -733,7 +797,7 @@ firrtl.circuit "MoveAcrossBlocks4" {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<8> // gets wired to localReset
|
%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
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset // blocks move of node
|
||||||
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node sym @theReset %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
// CHECK-NEXT: %localReset = firrtl.wire
|
// CHECK-NEXT: %localReset = firrtl.wire
|
||||||
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
|
// CHECK-NEXT: firrtl.when %ui1 : !firrtl.uint<1> {
|
||||||
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
// CHECK-NEXT: [[RV:%.+]] = firrtl.constant 0
|
||||||
|
@ -750,7 +814,7 @@ firrtl.circuit "MoveAcrossBlocks4" {
|
||||||
firrtl.circuit "SubAccess" {
|
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 {
|
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
|
// CHECK-LABEL: firrtl.module @SubAccess
|
||||||
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
portAnnotations = [[],[],[],[],[{class = "firrtl.transforms.DontTouchAnnotation"}, {class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
||||||
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<2>
|
%c1_ui8 = firrtl.constant 1 : !firrtl.uint<2>
|
||||||
%arr = firrtl.wire : !firrtl.vector<uint<8>, 1>
|
%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>
|
%reg6 = firrtl.regreset %clock, %init, %c1_ui8 : !firrtl.clock, !firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>
|
||||||
|
@ -772,7 +836,7 @@ firrtl.circuit "SubAccess" {
|
||||||
// CHECK-LABEL: firrtl.module @ZeroWidthRegister
|
// CHECK-LABEL: firrtl.module @ZeroWidthRegister
|
||||||
firrtl.circuit "ZeroWidthRegister" {
|
firrtl.circuit "ZeroWidthRegister" {
|
||||||
firrtl.module @ZeroWidthRegister(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
|
firrtl.module @ZeroWidthRegister(in %clock: !firrtl.clock, in %reset: !firrtl.asyncreset) attributes {
|
||||||
portAnnotations = [[],[{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]]} {
|
portAnnotations = [[],[{class = "circt.FullResetAnnotation", resetType = "async"}]]} {
|
||||||
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<0>
|
%reg = firrtl.reg %clock : !firrtl.clock, !firrtl.uint<0>
|
||||||
// CHECK-NEXT: [[TMP:%.+]] = firrtl.constant 0 : !firrtl.const.uint<0>
|
// CHECK-NEXT: [[TMP:%.+]] = firrtl.constant 0 : !firrtl.const.uint<0>
|
||||||
// CHECK-NEXT: %reg = firrtl.regreset %clock, %reset, [[TMP]]
|
// CHECK-NEXT: %reg = firrtl.regreset %clock, %reset, [[TMP]]
|
||||||
|
@ -1143,8 +1207,8 @@ firrtl.circuit "MovableNodeShouldDominateInstance" {
|
||||||
firrtl.connect %child_clock, %clock : !firrtl.clock
|
firrtl.connect %child_clock, %clock : !firrtl.clock
|
||||||
%ui1 = firrtl.constant 1 : !firrtl.uint<1>
|
%ui1 = firrtl.constant 1 : !firrtl.uint<1>
|
||||||
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset
|
%0 = firrtl.asAsyncReset %ui1 : (!firrtl.uint<1>) -> !firrtl.asyncreset
|
||||||
%localReset = firrtl.node %0 {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !firrtl.asyncreset
|
%localReset = firrtl.node %0 {annotations = [{class = "circt.FullResetAnnotation", resetType = "async"}]} : !firrtl.asyncreset
|
||||||
// CHECK: %localReset = firrtl.wire {annotations = [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]} : !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
|
// CHECK: %child_localReset, %child_clock = firrtl.instance child @Child(in localReset: !firrtl.asyncreset, in clock: !firrtl.clock
|
||||||
}
|
}
|
||||||
firrtl.module @Child(in %clock: !firrtl.clock) {
|
firrtl.module @Child(in %clock: !firrtl.clock) {
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
; RUN: firtool %s -parse-only | circt-opt -pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-resets))' | FileCheck %s --check-prefixes COMMON,POST-INFER-RESETS
|
; RUN: firtool %s -parse-only | circt-opt -pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-resets))' | FileCheck %s --check-prefixes COMMON,POST-INFER-RESETS
|
||||||
; RUN: firtool %s -parse-only | circt-opt -pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-resets,firrtl.module(firrtl-sfc-compat)))' | FileCheck %s --check-prefixes COMMON,POST-SFC-COMPAT
|
; RUN: firtool %s -parse-only | circt-opt -pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-resets,firrtl.module(firrtl-sfc-compat)))' | FileCheck %s --check-prefixes COMMON,POST-SFC-COMPAT
|
||||||
|
|
||||||
; Check that FullAsyncResetAnnotation exists after infer-resets pass
|
; Check that FullResetAnnotation exists after infer-resets pass
|
||||||
; but is deleted after sfc-compat
|
; but is deleted after sfc-compat
|
||||||
|
|
||||||
FIRRTL version 3.3.0
|
FIRRTL version 3.3.0
|
||||||
circuit test :%[[
|
circuit test :%[[
|
||||||
{ "class":"sifive.enterprise.firrtl.FullAsyncResetAnnotation",
|
{ "class":"circt.FullResetAnnotation",
|
||||||
"target":"~test|test>reset" },
|
"target":"~test|test>reset",
|
||||||
{ "class":"sifive.enterprise.firrtl.FullAsyncResetAnnotation",
|
"resetType":"async" },
|
||||||
"target":"~test|foo>r" }
|
{ "class":"circt.FullResetAnnotation",
|
||||||
|
"target":"~test|foo>r",
|
||||||
|
"resetType":"async" }
|
||||||
]]
|
]]
|
||||||
; COMMON-LABEL: module @test
|
; COMMON-LABEL: module @test
|
||||||
module test :
|
module test :
|
||||||
input clock : Clock
|
input clock : Clock
|
||||||
input reset : AsyncReset
|
input reset : AsyncReset
|
||||||
; POST-INFER-RESETS: [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]
|
; POST-INFER-RESETS: [{class = "circt.FullResetAnnotation", resetType = "async"}]
|
||||||
; POST-SFC-COMPAT-NOT: [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]
|
; POST-SFC-COMPAT-NOT: [{class = "circt.FullResetAnnotation", resetType = "async"}]
|
||||||
input in : { foo : UInt<8>, bar : UInt<8>}
|
input in : { foo : UInt<8>, bar : UInt<8>}
|
||||||
output out : { foo : UInt<8>, bar : UInt<8>}
|
output out : { foo : UInt<8>, bar : UInt<8>}
|
||||||
connect out, in
|
connect out, in
|
||||||
|
@ -28,7 +30,7 @@ circuit test :%[[
|
||||||
input in : { foo : UInt<8>, bar : UInt<8>}
|
input in : { foo : UInt<8>, bar : UInt<8>}
|
||||||
output out : { foo : UInt<8>, bar : UInt<8>}
|
output out : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
|
||||||
; POST-INFER-RESETS: [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]
|
; POST-INFER-RESETS: [{class = "circt.FullResetAnnotation", resetType = "async"}]
|
||||||
; POST-SFC-COMPAT-NOT: [{class = "sifive.enterprise.firrtl.FullAsyncResetAnnotation"}]
|
; POST-SFC-COMPAT-NOT: [{class = "circt.FullResetAnnotation", resetType = "async"}]
|
||||||
wire r : AsyncReset
|
wire r : AsyncReset
|
||||||
connect out, in
|
connect out, in
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
FIRRTL version 3.3.0
|
FIRRTL version 3.3.0
|
||||||
; CHECK-LABEL: module test(
|
; CHECK-LABEL: module test(
|
||||||
circuit test :%[[{
|
circuit test :%[[{
|
||||||
"class":"sifive.enterprise.firrtl.FullAsyncResetAnnotation",
|
"class":"circt.FullResetAnnotation",
|
||||||
"target":"~test|test>reset"
|
"target":"~test|test>reset",
|
||||||
|
"resetType":"async"
|
||||||
}]]
|
}]]
|
||||||
module test :
|
module test :
|
||||||
input clock : Clock
|
input clock : Clock
|
||||||
|
@ -31,8 +32,9 @@ circuit test :%[[{
|
||||||
; CHECK-LABEL: module test_wire(
|
; CHECK-LABEL: module test_wire(
|
||||||
FIRRTL version 3.3.0
|
FIRRTL version 3.3.0
|
||||||
circuit test_wire :%[[{
|
circuit test_wire :%[[{
|
||||||
"class":"sifive.enterprise.firrtl.FullAsyncResetAnnotation",
|
"class":"circt.FullResetAnnotation",
|
||||||
"target":"~test_wire|test_wire>reset"
|
"target":"~test_wire|test_wire>reset",
|
||||||
|
"resetType":"async"
|
||||||
}]]
|
}]]
|
||||||
module test_wire :
|
module test_wire :
|
||||||
input clock : Clock
|
input clock : Clock
|
||||||
|
@ -56,3 +58,63 @@ circuit test_wire :%[[{
|
||||||
connect reg1, in
|
connect reg1, in
|
||||||
connect reg2, reg1
|
connect reg2, reg1
|
||||||
connect out, reg2
|
connect out, reg2
|
||||||
|
|
||||||
|
;// -----
|
||||||
|
; CHECK-LABEL: module test_sync(
|
||||||
|
FIRRTL version 3.3.0
|
||||||
|
circuit test_sync :%[[{
|
||||||
|
"class":"circt.FullResetAnnotation",
|
||||||
|
"target":"~test_sync|test_sync>reset",
|
||||||
|
"resetType":"sync"
|
||||||
|
}]]
|
||||||
|
module test_sync :
|
||||||
|
input clock : Clock
|
||||||
|
input reset : UInt<1>
|
||||||
|
input in : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
output out : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
|
||||||
|
wire reg1_w : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
invalidate reg1_w.bar
|
||||||
|
invalidate reg1_w.foo
|
||||||
|
connect reg1_w.foo, UInt<8>(0hc)
|
||||||
|
invalidate reg1_w.bar
|
||||||
|
; CHECK: always @(posedge clock) begin
|
||||||
|
; CHECK-NEXT: if (reset) begin
|
||||||
|
; CHECK-NEXT: reg1_foo <= 8'hC;
|
||||||
|
; CHECK-NEXT: reg1_bar <= 8'h0;
|
||||||
|
regreset reg1 : { foo : UInt<8>, bar : UInt<8>}, clock, reset, reg1_w
|
||||||
|
wire reg2 : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
connect reg1, in
|
||||||
|
connect reg2, reg1
|
||||||
|
connect out, reg2
|
||||||
|
|
||||||
|
;// -----
|
||||||
|
; CHECK-LABEL: module test_wire_sync(
|
||||||
|
FIRRTL version 3.3.0
|
||||||
|
circuit test_wire_sync :%[[{
|
||||||
|
"class":"circt.FullResetAnnotation",
|
||||||
|
"target":"~test_wire_sync|test_wire_sync>reset",
|
||||||
|
"resetType":"sync"
|
||||||
|
}]]
|
||||||
|
module test_wire_sync :
|
||||||
|
input clock : Clock
|
||||||
|
input rst : UInt<1>
|
||||||
|
input in : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
output out : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
|
||||||
|
node reset = rst
|
||||||
|
|
||||||
|
wire reg1_w : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
invalidate reg1_w.bar
|
||||||
|
invalidate reg1_w.foo
|
||||||
|
connect reg1_w.foo, UInt<8>(0hc)
|
||||||
|
invalidate reg1_w.bar
|
||||||
|
; CHECK: always @(posedge clock) begin
|
||||||
|
; CHECK-NEXT: if (rst) begin
|
||||||
|
; CHECK-NEXT: reg1_foo <= 8'hC;
|
||||||
|
; CHECK-NEXT: reg1_bar <= 8'h0;
|
||||||
|
regreset reg1 : { foo : UInt<8>, bar : UInt<8>}, clock, reset, reg1_w
|
||||||
|
wire reg2 : { foo : UInt<8>, bar : UInt<8>}
|
||||||
|
connect reg1, in
|
||||||
|
connect reg2, reg1
|
||||||
|
connect out, reg2
|
||||||
|
|
Loading…
Reference in New Issue