[FIRRTL] Preserve/Tap all "Named" Nodes or Wires (#2676)

Change end-to-end FIRRTL compilation behavior to preserve (via tapping) all
nodes and wires which are "named".  A "named" node or wire is one whose name
does not begin with an underscore.  Tapping is done by creating a "shadow node"
that is assigned the value of the actual wire and marked "don't touch".

This is done to enable better debug-ability of Chisel designs by enabling users
to always have references to named things they define in Chisel.  More
specifically, anytime a Chisel user defines a `val foo = <expression>`, CIRCT
will now produce a wire called "foo" in the output Verilog.

Add a parser option for controlling whether or not "named" wires and
nodes will be preserved from FIRRTL to Verilog.

Add a firtool command-line option for disabling name preservation during
FIRRTL parsing.

Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This commit is contained in:
Schuyler Eldridge 2022-02-25 18:34:27 -05:00 committed by GitHub
parent 727db57a3a
commit 106815aea4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 9 deletions

View File

@ -38,6 +38,11 @@ struct FIRParserOptions {
/// This, along with numOMIRFiles provides structure to the buffers in the
/// source manager.
unsigned numAnnotationFiles;
/// If true, then the parser will NOT generate debug taps for "named" wires
/// and nodes. A "named" wire/node is one whose name does NOT beging with a
/// leading "_". If false, debug-ability is greatly increased. If true, much
/// more compact Verilog will be generated.
bool disableNamePreservation = true;
};
mlir::OwningOpRef<mlir::ModuleOp> importFIRFile(llvm::SourceMgr &sourceMgr,

View File

@ -2996,6 +2996,8 @@ ParseResult FIRStmtParser::parseMem(unsigned memIndent) {
return moduleContext.addSymbolEntry(id, entryID, startTok.getLoc());
}
static bool isNamed(StringRef id) { return !id.startswith("_"); }
/// node ::= 'node' id '=' exp info?
ParseResult FIRStmtParser::parseNode() {
auto startTok = consumeToken(FIRToken::kw_node);
@ -3040,8 +3042,19 @@ ParseResult FIRStmtParser::parseNode() {
moduleContext.targetsInModule, initializerType);
auto sym = getSymbolIfRequired(annotations, id);
auto result = builder.create<NodeOp>(initializer.getType(), initializer, id,
auto isNamed =
!getConstants().options.disableNamePreservation && ::isNamed(id);
auto result = builder.create<NodeOp>(initializer.getType(), initializer,
isNamed ? (Twine("_") + id).str() : id,
annotations, sym);
// If the node is named, then add a debug tap.
//
// TODO: Change this once the FIRRTL spec supports "named" vs. "unnamed"
// nodes.
if (isNamed)
builder.create<NodeOp>(
initializer.getType(), result, id, getConstants().emptyArrayAttr,
StringAttr::get(annotations.getContext(), modNameSpace.newName(id)));
return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
}
@ -3070,7 +3083,26 @@ ParseResult FIRStmtParser::parseWire() {
moduleContext.targetsInModule, type);
auto sym = getSymbolIfRequired(annotations, id);
auto result = builder.create<WireOp>(type, id, annotations, sym);
auto isNamed =
!getConstants().options.disableNamePreservation && ::isNamed(id);
auto result = builder.create<WireOp>(
type, isNamed ? (Twine("_") + id).str() : id, annotations, sym);
// If the wire is named, then add a debug tap.
//
// TODO: Change this once the FIRRTL spec supports "named" vs. "unnamed"
// wires.
if (isNamed) {
if (type.isPassive())
builder.create<NodeOp>(
type, result, id, getConstants().emptyArrayAttr,
StringAttr::get(annotations.getContext(), modNameSpace.newName(id)));
else {
auto debug = builder.create<WireOp>(
type.getPassiveType(), id, getConstants().emptyArrayAttr,
StringAttr::get(annotations.getContext(), modNameSpace.newName(id)));
builder.create<ConnectOp>(debug, result);
}
}
return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
}

View File

@ -1,7 +1,7 @@
; RUN: firtool --firrtl-grand-central --verilog --annotation-file %S/Wire.anno.json --annotation-file %S/Extract.anno.json %s | FileCheck %s --check-prefixes CHECK,EXTRACT
; RUN: firtool --firrtl-grand-central --verilog --annotation-file %S/Wire.anno.json %s | FileCheck %s --check-prefixes CHECK,NOEXTRACT
; RUN: firtool --firrtl-grand-central --verilog --annotation-file %S/Wire.anno.json --annotation-file %S/Extract.anno.json %s --annotation-file %S/YAML.anno.json | FileCheck %s --check-prefixes YAML
; RUN: firtool --firrtl-grand-central --split-verilog --annotation-file %S/Wire.anno.json %s -o %t.folder > %t && cat %t.folder/MyView_companion.sv | FileCheck %s --check-prefixes MYVIEW_COMPANION
; RUN: firtool --firrtl-grand-central --disable-name-preservation --verilog --annotation-file %S/Wire.anno.json --annotation-file %S/Extract.anno.json %s | FileCheck %s --check-prefixes CHECK,EXTRACT
; RUN: firtool --firrtl-grand-central --disable-name-preservation --verilog --annotation-file %S/Wire.anno.json %s | FileCheck %s --check-prefixes CHECK,NOEXTRACT
; RUN: firtool --firrtl-grand-central --disable-name-preservation --verilog --annotation-file %S/Wire.anno.json --annotation-file %S/Extract.anno.json %s --annotation-file %S/YAML.anno.json | FileCheck %s --check-prefixes YAML
; RUN: firtool --firrtl-grand-central --disable-name-preservation --split-verilog --annotation-file %S/Wire.anno.json %s -o %t.folder > %t && cat %t.folder/MyView_companion.sv | FileCheck %s --check-prefixes MYVIEW_COMPANION
circuit Top :
module Submodule :

View File

@ -1,4 +1,4 @@
; RUN: firtool --firrtl-grand-central --verilog %s | FileCheck %s
; RUN: firtool --firrtl-grand-central --disable-name-preservation --verilog %s | FileCheck %s
; See https://github.com/llvm/circt/issues/2691
circuit Top : %[[{

View File

@ -1,4 +1,4 @@
; RUN: firtool %s --annotation-file %S/signal-mappings-subCircuit.json --firrtl-grand-central --verilog | FileCheck %s
; RUN: firtool %s --annotation-file %S/signal-mappings-subCircuit.json --disable-name-preservation --firrtl-grand-central --verilog | FileCheck %s
; Subcircuit:

View File

@ -1,4 +1,4 @@
; RUN: firtool --split-input-file --verify-diagnostics %s
; RUN: firtool --disable-name-preservation --split-input-file --verify-diagnostics %s
; Tests extracted from:
; - test/scala/firrtlTests/WidthSpec.scala

View File

@ -0,0 +1,37 @@
; RUN: firtool %s | FileCheck %s --check-prefixes=CHECK,NAMES
; RUN: firtool %s -disable-name-preservation | FileCheck %s --check-prefixes=CHECK,NO_NAMES
circuit Foo:
; CHECK-LABEL: module Foo
module Foo:
input a: {a: UInt<1>, flip b: UInt<1>}
output b: {a: UInt<1>, flip b: UInt<1>}
; Unnamed wires are always removed.
; CHECK-NOT: wire _x_a;
; CHECK-NOT: wire _x_b;
wire _x: {a: UInt<1>, flip b: UInt<1>}
_x <= a
; Default behavior is to preserve named wires.
; NAMES: wire x_a;
; NAMES: wire x_b;
; With -disable-name-preservation, named wires are removed.
; NO_NAMES-NOT: wire x_b;
; NO_NAMES-NOT: wire x_a;
wire x: {a: UInt<1>, flip b: UInt<1>}
x <= _x
; Unnamed nodes are always removed.
; CHECK-NOT: wire _y_a;
node _y_a = x.a
; Default behavior is to preserve named nodes.
; NAMES: wire y;
; With -disable-name-preservation, named nodes are removed.
; NO-NAMES-NOT: wire y;
node y = _y_a
b.a <= y
x.b <= b.b

View File

@ -102,6 +102,11 @@ static cl::opt<bool> disableAnnotationsUnknown(
"disable-annotation-unknown",
cl::desc("Ignore unknown annotations when parsing"), cl::init(false));
static cl::opt<bool> disableNamePreservation(
"disable-name-preservation",
cl::desc("Don't generate debug taps for named FIRRTL wires and nodes"),
cl::init(false));
static cl::opt<bool>
emitMetadata("emit-metadata",
cl::desc("emit metadata for metadata annotations"),
@ -381,6 +386,7 @@ processBuffer(MLIRContext &context, TimingScope &ts, llvm::SourceMgr &sourceMgr,
options.ignoreInfoLocators = ignoreFIRLocations;
options.rawAnnotations = newAnno;
options.numAnnotationFiles = numAnnotationFiles;
options.disableNamePreservation = disableNamePreservation;
module = importFIRFile(sourceMgr, &context, options);
} else {
auto parserTimer = ts.nest("MLIR Parser");