mirror of https://github.com/llvm/circt.git
810 lines
33 KiB
C++
810 lines
33 KiB
C++
//===- Firtool.cpp - Definitions for the firtool pipeline setup -*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "circt/Firtool/Firtool.h"
|
|
#include "circt/Conversion/Passes.h"
|
|
#include "circt/Dialect/FIRRTL/FIRRTLOps.h"
|
|
#include "circt/Dialect/FIRRTL/Passes.h"
|
|
#include "circt/Dialect/HW/HWPasses.h"
|
|
#include "circt/Dialect/OM/OMPasses.h"
|
|
#include "circt/Dialect/SV/SVPasses.h"
|
|
#include "circt/Dialect/Seq/SeqPasses.h"
|
|
#include "circt/Dialect/Verif/VerifPasses.h"
|
|
#include "circt/Support/Passes.h"
|
|
#include "circt/Transforms/Passes.h"
|
|
#include "mlir/Transforms/Passes.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
using namespace llvm;
|
|
using namespace circt;
|
|
|
|
LogicalResult firtool::populatePreprocessTransforms(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt) {
|
|
// Legalize away "open" aggregates to hw-only versions.
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerOpenAggsPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createResolvePathsPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerFIRRTLAnnotationsPass(
|
|
opt.shouldDisableUnknownAnnotations(),
|
|
opt.shouldDisableClasslessAnnotations(),
|
|
opt.shouldLowerNoRefTypePortAnnotations(),
|
|
opt.shouldAllowAddingPortsOnPublic()));
|
|
|
|
if (opt.shouldEnableDebugInfo())
|
|
pm.nest<firrtl::CircuitOp>().addNestedPass<firrtl::FModuleOp>(
|
|
firrtl::createMaterializeDebugInfoPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
firrtl::createLowerIntmodulesPass(opt.shouldFixupEICGWrapper()));
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createLowerIntrinsicsPass());
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateCHIRRTLToLowFIRRTL(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt,
|
|
StringRef inputFilename) {
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerSignaturesPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInjectDUTHierarchyPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createPassiveWiresPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createDropNamesPass(opt.getPreserveMode()));
|
|
|
|
if (!opt.shouldDisableOptimization())
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
mlir::createCSEPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createLowerCHIRRTLPass());
|
|
|
|
// Run LowerMatches before InferWidths, as the latter does not support the
|
|
// match statement, but it does support what they lower to.
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createLowerMatchesPass());
|
|
|
|
// Width inference creates canonicalization opportunities.
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferWidthsPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
firrtl::createMemToRegOfVecPass(opt.shouldReplaceSequentialMemories(),
|
|
opt.shouldIgnoreReadEnableMemories()));
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferResetsPass());
|
|
|
|
if (opt.shouldExportChiselInterface()) {
|
|
StringRef outdir = opt.getChiselInterfaceOutputDirectory();
|
|
if (opt.isDefaultOutputFilename() && outdir.empty()) {
|
|
pm.nest<firrtl::CircuitOp>().addPass(createExportChiselInterfacePass());
|
|
} else {
|
|
if (outdir.empty())
|
|
outdir = opt.getOutputFilename();
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
createExportSplitChiselInterfacePass(outdir));
|
|
}
|
|
}
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createDropConstPass());
|
|
|
|
if (opt.shouldDedup())
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createDedupPass());
|
|
|
|
if (opt.shouldConvertVecOfBundle()) {
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createLowerFIRRTLTypesPass(
|
|
firrtl::PreserveAggregate::All, firrtl::PreserveAggregate::All));
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createVBToBVPass());
|
|
}
|
|
|
|
if (!opt.shouldLowerMemories())
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createFlattenMemoryPass());
|
|
|
|
// The input mlir file could be firrtl dialect so we might need to clean
|
|
// things up.
|
|
// pm.addNestedPass<firrtl::CircuitOp>(firrtl::createLowerSignaturesPass());
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createLowerFIRRTLTypesPass(
|
|
opt.getPreserveAggregate(), firrtl::PreserveAggregate::None));
|
|
|
|
{
|
|
auto &modulePM = pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>();
|
|
modulePM.addPass(firrtl::createExpandWhensPass());
|
|
modulePM.addPass(firrtl::createSFCCompatPass());
|
|
}
|
|
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createCheckCombLoopsPass());
|
|
|
|
// Must run this pass after all diagnostic passes have run, otherwise it can
|
|
// hide errors.
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createSpecializeLayersPass());
|
|
|
|
// Run after inference, layer specialization.
|
|
if (opt.shouldConvertProbesToSignals())
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createProbesToSignalsPass());
|
|
|
|
{
|
|
auto &modulePM = pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>();
|
|
modulePM.addPass(firrtl::createLayerMergePass());
|
|
modulePM.addPass(firrtl::createLayerSinkPass());
|
|
}
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerLayersPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInlinerPass());
|
|
|
|
// Preset the random initialization parameters for each module. The current
|
|
// implementation assumes it can run at a time where every register is
|
|
// currently in the final module it will be emitted in, all registers have
|
|
// been created, and no registers have yet been removed.
|
|
if (opt.isRandomEnabled(FirtoolOptions::RandomKind::Reg))
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createRandomizeRegisterInitPass());
|
|
|
|
// If we parsed a FIRRTL file and have optimizations enabled, clean it up.
|
|
if (!opt.shouldDisableOptimization())
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
createSimpleCanonicalizerPass());
|
|
|
|
// Run the infer-rw pass, which merges read and write ports of a memory with
|
|
// mutually exclusive enables.
|
|
if (!opt.shouldDisableOptimization())
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createInferReadWritePass());
|
|
|
|
if (opt.shouldReplaceSequentialMemories())
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerMemoryPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createPrefixModulesPass());
|
|
|
|
if (opt.shouldAddCompanionAssume())
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
circt::firrtl::createCreateCompanionAssume());
|
|
|
|
if (!opt.shouldDisableOptimization())
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createIMConstPropPass());
|
|
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createAddSeqMemPortsPass());
|
|
|
|
pm.addPass(firrtl::createCreateSiFiveMetadataPass(
|
|
opt.shouldReplaceSequentialMemories(),
|
|
opt.getReplaceSequentialMemoriesFile()));
|
|
|
|
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createExtractInstancesPass());
|
|
|
|
// Run passes to resolve Grand Central features. This should run before
|
|
// BlackBoxReader because Grand Central needs to inform BlackBoxReader where
|
|
// certain black boxes should be placed. Note: all Grand Central Taps related
|
|
// collateral is resolved entirely by LowerAnnotations.
|
|
pm.addNestedPass<firrtl::CircuitOp>(
|
|
firrtl::createGrandCentralPass(opt.getCompanionMode()));
|
|
|
|
// Read black box source files into the IR.
|
|
StringRef blackBoxRoot = opt.getBlackBoxRootPath().empty()
|
|
? llvm::sys::path::parent_path(inputFilename)
|
|
: opt.getBlackBoxRootPath();
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
firrtl::createBlackBoxReaderPass(blackBoxRoot));
|
|
|
|
// Run SymbolDCE as late as possible, but before InnerSymbolDCE. This is for
|
|
// hierpathop's and just for general cleanup.
|
|
pm.addNestedPass<firrtl::CircuitOp>(mlir::createSymbolDCEPass());
|
|
|
|
// Run InnerSymbolDCE as late as possible, but before IMDCE.
|
|
pm.addPass(firrtl::createInnerSymbolDCEPass());
|
|
|
|
// The above passes, IMConstProp in particular, introduce additional
|
|
// canonicalization opportunities that we should pick up here before we
|
|
// proceed to output-specific pipelines.
|
|
if (!opt.shouldDisableOptimization()) {
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
createSimpleCanonicalizerPass());
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
circt::firrtl::createRegisterOptimizerPass());
|
|
// Re-run IMConstProp to propagate constants produced by register
|
|
// optimizations.
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createIMConstPropPass());
|
|
pm.addPass(firrtl::createIMDeadCodeElimPass());
|
|
}
|
|
|
|
if (opt.shouldEmitOMIR())
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
firrtl::createEmitOMIRPass(opt.getOmirOutputFile()));
|
|
|
|
// Always run this, required for legalization.
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createMergeConnectionsPass(
|
|
!opt.shouldDisableAggressiveMergeConnections()));
|
|
|
|
if (!opt.shouldDisableOptimization())
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
firrtl::createVectorizationPass());
|
|
|
|
auto outputFilename = opt.getOutputFilename();
|
|
if (outputFilename == "-")
|
|
outputFilename = "";
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
firrtl::createAssignOutputDirsPass(outputFilename));
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateLowFIRRTLToHW(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt) {
|
|
// Remove TraceAnnotations and write their updated paths to an output
|
|
// annotation file.
|
|
pm.nest<firrtl::CircuitOp>().addPass(
|
|
firrtl::createResolveTracesPass(opt.getOutputAnnotationFilename()));
|
|
|
|
// Lower the ref.resolve and ref.send ops and remove the RefType ports.
|
|
// LowerToHW cannot handle RefType so, this pass must be run to remove all
|
|
// RefType ports and ops.
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerXMRPass());
|
|
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerDPIPass());
|
|
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerClassesPass());
|
|
pm.nest<firrtl::CircuitOp>().addPass(om::createVerifyObjectFieldsPass());
|
|
|
|
// Check for static asserts.
|
|
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
|
|
circt::firrtl::createLintingPass());
|
|
|
|
pm.addPass(createLowerFIRRTLToHWPass(opt.shouldEnableAnnotationWarning(),
|
|
opt.getVerificationFlavor()));
|
|
|
|
if (!opt.shouldDisableOptimization()) {
|
|
auto &modulePM = pm.nest<hw::HWModuleOp>();
|
|
modulePM.addPass(mlir::createCSEPass());
|
|
modulePM.addPass(createSimpleCanonicalizerPass());
|
|
}
|
|
|
|
// Check inner symbols and inner refs.
|
|
pm.addPass(hw::createVerifyInnerRefNamespacePass());
|
|
|
|
// Check OM object fields.
|
|
pm.addPass(om::createVerifyObjectFieldsPass());
|
|
|
|
// Run the verif op verification pass
|
|
pm.addNestedPass<hw::HWModuleOp>(verif::createVerifyClockedAssertLikePass());
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateHWToSV(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt) {
|
|
|
|
if (opt.shouldExtractTestCode())
|
|
pm.addPass(sv::createSVExtractTestCodePass(
|
|
opt.shouldEtcDisableInstanceExtraction(),
|
|
opt.shouldEtcDisableRegisterExtraction(),
|
|
opt.shouldEtcDisableModuleInlining()));
|
|
|
|
pm.addPass(seq::createExternalizeClockGatePass(opt.getClockGateOptions()));
|
|
pm.addPass(circt::createLowerSimToSVPass());
|
|
pm.addPass(circt::createLowerSeqToSVPass(
|
|
{/*disableRegRandomization=*/!opt.isRandomEnabled(
|
|
FirtoolOptions::RandomKind::Reg),
|
|
/*disableMemRandomization=*/
|
|
!opt.isRandomEnabled(FirtoolOptions::RandomKind::Mem),
|
|
/*emitSeparateAlwaysBlocks=*/
|
|
opt.shouldEmitSeparateAlwaysBlocks()}));
|
|
pm.addNestedPass<hw::HWModuleOp>(createLowerVerifToSVPass());
|
|
pm.addPass(seq::createHWMemSimImplPass(
|
|
{/*disableMemRandomization=*/!opt.isRandomEnabled(
|
|
FirtoolOptions::RandomKind::Mem),
|
|
/*disableRegRandomization=*/
|
|
!opt.isRandomEnabled(FirtoolOptions::RandomKind::Reg),
|
|
/*replSeqMem=*/opt.shouldReplaceSequentialMemories(),
|
|
/*readEnableMode=*/opt.shouldIgnoreReadEnableMemories()
|
|
? seq::ReadEnableMode::Ignore
|
|
: seq::ReadEnableMode::Undefined,
|
|
/*addMuxPragmas=*/opt.shouldAddMuxPragmas(),
|
|
/*addVivadoRAMAddressConflictSynthesisBugWorkaround=*/
|
|
opt.shouldAddVivadoRAMAddressConflictSynthesisBugWorkaround()}));
|
|
|
|
// If enabled, run the optimizer.
|
|
if (!opt.shouldDisableOptimization()) {
|
|
auto &modulePM = pm.nest<hw::HWModuleOp>();
|
|
modulePM.addPass(mlir::createCSEPass());
|
|
modulePM.addPass(createSimpleCanonicalizerPass());
|
|
modulePM.addPass(mlir::createCSEPass());
|
|
modulePM.addPass(sv::createHWCleanupPass(
|
|
/*mergeAlwaysBlocks=*/!opt.shouldEmitSeparateAlwaysBlocks()));
|
|
}
|
|
|
|
// Check inner symbols and inner refs.
|
|
pm.addPass(hw::createVerifyInnerRefNamespacePass());
|
|
|
|
// Check OM object fields.
|
|
pm.addPass(om::createVerifyObjectFieldsPass());
|
|
|
|
return success();
|
|
}
|
|
|
|
namespace detail {
|
|
LogicalResult
|
|
populatePrepareForExportVerilog(mlir::PassManager &pm,
|
|
const firtool::FirtoolOptions &opt) {
|
|
|
|
// Run the verif op verification pass
|
|
pm.addNestedPass<hw::HWModuleOp>(verif::createVerifyClockedAssertLikePass());
|
|
|
|
// Legalize unsupported operations within the modules.
|
|
pm.nest<hw::HWModuleOp>().addPass(sv::createHWLegalizeModulesPass());
|
|
|
|
// Tidy up the IR to improve verilog emission quality.
|
|
if (!opt.shouldDisableOptimization())
|
|
pm.nest<hw::HWModuleOp>().addPass(sv::createPrettifyVerilogPass());
|
|
|
|
if (opt.shouldStripFirDebugInfo())
|
|
pm.addPass(circt::createStripDebugInfoWithPredPass([](mlir::Location loc) {
|
|
if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
|
|
return fileLoc.getFilename().getValue().ends_with(".fir");
|
|
return false;
|
|
}));
|
|
|
|
if (opt.shouldStripDebugInfo())
|
|
pm.addPass(circt::createStripDebugInfoWithPredPass(
|
|
[](mlir::Location loc) { return true; }));
|
|
|
|
// Emit module and testbench hierarchy JSON files.
|
|
if (opt.shouldExportModuleHierarchy())
|
|
pm.addPass(sv::createHWExportModuleHierarchyPass());
|
|
|
|
// Check inner symbols and inner refs.
|
|
pm.addPass(hw::createVerifyInnerRefNamespacePass());
|
|
|
|
// Check OM object fields.
|
|
pm.addPass(om::createVerifyObjectFieldsPass());
|
|
|
|
return success();
|
|
}
|
|
} // namespace detail
|
|
|
|
LogicalResult
|
|
firtool::populateExportVerilog(mlir::PassManager &pm, const FirtoolOptions &opt,
|
|
std::unique_ptr<llvm::raw_ostream> os) {
|
|
if (failed(::detail::populatePrepareForExportVerilog(pm, opt)))
|
|
return failure();
|
|
|
|
pm.addPass(createExportVerilogPass(std::move(os)));
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateExportVerilog(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt,
|
|
llvm::raw_ostream &os) {
|
|
if (failed(::detail::populatePrepareForExportVerilog(pm, opt)))
|
|
return failure();
|
|
|
|
pm.addPass(createExportVerilogPass(os));
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateExportSplitVerilog(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt,
|
|
llvm::StringRef directory) {
|
|
if (failed(::detail::populatePrepareForExportVerilog(pm, opt)))
|
|
return failure();
|
|
|
|
pm.addPass(createExportSplitVerilogPass(directory));
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateFinalizeIR(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt) {
|
|
pm.addPass(firrtl::createFinalizeIRPass());
|
|
pm.addPass(om::createFreezePathsPass());
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult firtool::populateHWToBTOR2(mlir::PassManager &pm,
|
|
const FirtoolOptions &opt,
|
|
llvm::raw_ostream &os) {
|
|
pm.addNestedPass<hw::HWModuleOp>(circt::createLowerLTLToCorePass());
|
|
pm.addNestedPass<hw::HWModuleOp>(circt::verif::createPrepareForFormalPass());
|
|
pm.addPass(circt::hw::createFlattenModulesPass());
|
|
pm.addNestedPass<hw::HWModuleOp>(circt::createConvertHWToBTOR2Pass(os));
|
|
return success();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// FIRTOOL CommandLine Options
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
/// This struct contains command line options that can be used to initialize
|
|
/// various bits of a Firtool pipeline. This uses a struct wrapper to avoid the
|
|
/// need for global command line options.
|
|
struct FirtoolCmdOptions {
|
|
llvm::cl::opt<std::string> outputFilename{
|
|
"o",
|
|
llvm::cl::desc("Output filename, or directory for split output"),
|
|
llvm::cl::value_desc("filename"),
|
|
llvm::cl::init("-"),
|
|
};
|
|
|
|
llvm::cl::opt<bool> disableAnnotationsUnknown{
|
|
"disable-annotation-unknown",
|
|
llvm::cl::desc("Ignore unknown annotations when parsing"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> disableAnnotationsClassless{
|
|
"disable-annotation-classless",
|
|
llvm::cl::desc("Ignore annotations without a class when parsing"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> lowerAnnotationsNoRefTypePorts{
|
|
"lower-annotations-no-ref-type-ports",
|
|
llvm::cl::desc(
|
|
"Create real ports instead of ref type ports when resolving "
|
|
"wiring problems inside the LowerAnnotations pass"),
|
|
llvm::cl::init(false), llvm::cl::Hidden};
|
|
|
|
llvm::cl::opt<bool> allowAddingPortsOnPublic{
|
|
"allow-adding-ports-on-public-modules",
|
|
llvm::cl::desc("Allow adding ports to public modules"),
|
|
llvm::cl::init(false), llvm::cl::Hidden};
|
|
|
|
llvm::cl::opt<bool> probesToSignals{
|
|
"probes-to-signals",
|
|
llvm::cl::desc("Convert probes to non-probe signals"),
|
|
llvm::cl::init(false), llvm::cl::Hidden};
|
|
|
|
llvm::cl::opt<circt::firrtl::PreserveAggregate::PreserveMode>
|
|
preserveAggregate{
|
|
"preserve-aggregate",
|
|
llvm::cl::desc("Specify input file format:"),
|
|
llvm::cl::values(
|
|
clEnumValN(circt::firrtl::PreserveAggregate::None, "none",
|
|
"Preserve no aggregate"),
|
|
clEnumValN(circt::firrtl::PreserveAggregate::OneDimVec, "1d-vec",
|
|
"Preserve only 1d vectors of ground type"),
|
|
clEnumValN(circt::firrtl::PreserveAggregate::Vec, "vec",
|
|
"Preserve only vectors"),
|
|
clEnumValN(circt::firrtl::PreserveAggregate::All, "all",
|
|
"Preserve vectors and bundles")),
|
|
llvm::cl::init(circt::firrtl::PreserveAggregate::None),
|
|
};
|
|
|
|
llvm::cl::opt<firrtl::PreserveValues::PreserveMode> preserveMode{
|
|
"preserve-values",
|
|
llvm::cl::desc("Specify the values which can be optimized away"),
|
|
llvm::cl::values(
|
|
clEnumValN(firrtl::PreserveValues::Strip, "strip",
|
|
"Strip all names. No name is preserved"),
|
|
clEnumValN(firrtl::PreserveValues::None, "none",
|
|
"Names could be preserved by best-effort unlike `strip`"),
|
|
clEnumValN(firrtl::PreserveValues::Named, "named",
|
|
"Preserve values with meaningful names"),
|
|
clEnumValN(firrtl::PreserveValues::All, "all",
|
|
"Preserve all values")),
|
|
llvm::cl::init(firrtl::PreserveValues::None)};
|
|
|
|
llvm::cl::opt<bool> enableDebugInfo{
|
|
"g", llvm::cl::desc("Enable the generation of debug information"),
|
|
llvm::cl::init(false)};
|
|
|
|
// Build mode options.
|
|
llvm::cl::opt<firtool::FirtoolOptions::BuildMode> buildMode{
|
|
"O", llvm::cl::desc("Controls how much optimization should be performed"),
|
|
llvm::cl::values(clEnumValN(firtool::FirtoolOptions::BuildModeDebug,
|
|
"debug",
|
|
"Compile with only necessary optimizations"),
|
|
clEnumValN(firtool::FirtoolOptions::BuildModeRelease,
|
|
"release", "Compile with optimizations")),
|
|
llvm::cl::init(firtool::FirtoolOptions::BuildModeDefault)};
|
|
|
|
llvm::cl::opt<bool> disableOptimization{
|
|
"disable-opt",
|
|
llvm::cl::desc("Disable optimizations"),
|
|
};
|
|
|
|
llvm::cl::opt<bool> exportChiselInterface{
|
|
"export-chisel-interface",
|
|
llvm::cl::desc("Generate a Scala Chisel interface to the top level "
|
|
"module of the firrtl circuit"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<std::string> chiselInterfaceOutDirectory{
|
|
"chisel-interface-out-dir",
|
|
llvm::cl::desc(
|
|
"The output directory for generated Chisel interface files"),
|
|
llvm::cl::init("")};
|
|
|
|
llvm::cl::opt<bool> vbToBV{
|
|
"vb-to-bv",
|
|
llvm::cl::desc("Transform vectors of bundles to bundles of vectors"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> noDedup{
|
|
"no-dedup",
|
|
llvm::cl::desc("Disable deduplication of structurally identical modules"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<firrtl::CompanionMode> companionMode{
|
|
"grand-central-companion-mode",
|
|
llvm::cl::desc("Specifies the handling of Grand Central companions"),
|
|
::llvm::cl::values(
|
|
clEnumValN(firrtl::CompanionMode::Bind, "bind",
|
|
"Lower companion instances to SystemVerilog binds"),
|
|
clEnumValN(firrtl::CompanionMode::Instantiate, "instantiate",
|
|
"Instantiate companions in the design"),
|
|
clEnumValN(firrtl::CompanionMode::Drop, "drop",
|
|
"Remove companions from the design")),
|
|
llvm::cl::init(firrtl::CompanionMode::Bind),
|
|
llvm::cl::Hidden,
|
|
};
|
|
|
|
llvm::cl::opt<bool> disableAggressiveMergeConnections{
|
|
"disable-aggressive-merge-connections",
|
|
llvm::cl::desc(
|
|
"Disable aggressive merge connections (i.e. merge all field-level "
|
|
"connections into bulk connections)"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> emitOMIR{
|
|
"emit-omir", llvm::cl::desc("Emit OMIR annotations to a JSON file"),
|
|
llvm::cl::init(true)};
|
|
|
|
llvm::cl::opt<std::string> omirOutFile{
|
|
"output-omir", llvm::cl::desc("File name for the output omir"),
|
|
llvm::cl::init("")};
|
|
|
|
llvm::cl::opt<bool> lowerMemories{
|
|
"lower-memories",
|
|
llvm::cl::desc("Lower memories to have memories with masks as an "
|
|
"array with one memory per ground type"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<std::string> blackBoxRootPath{
|
|
"blackbox-path",
|
|
llvm::cl::desc(
|
|
"Optional path to use as the root of black box annotations"),
|
|
llvm::cl::value_desc("path"),
|
|
llvm::cl::init(""),
|
|
};
|
|
|
|
llvm::cl::opt<bool> replSeqMem{
|
|
"repl-seq-mem",
|
|
llvm::cl::desc("Replace the seq mem for macro replacement and emit "
|
|
"relevant metadata"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<std::string> replSeqMemFile{
|
|
"repl-seq-mem-file", llvm::cl::desc("File name for seq mem metadata"),
|
|
llvm::cl::init("")};
|
|
|
|
llvm::cl::opt<bool> extractTestCode{
|
|
"extract-test-code", llvm::cl::desc("Run the extract test code pass"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> ignoreReadEnableMem{
|
|
"ignore-read-enable-mem",
|
|
llvm::cl::desc("Ignore the read enable signal, instead of "
|
|
"assigning X on read disable"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<firtool::FirtoolOptions::RandomKind> disableRandom{
|
|
llvm::cl::desc(
|
|
"Disable random initialization code (may break semantics!)"),
|
|
llvm::cl::values(
|
|
clEnumValN(firtool::FirtoolOptions::RandomKind::Mem,
|
|
"disable-mem-randomization",
|
|
"Disable emission of memory randomization code"),
|
|
clEnumValN(firtool::FirtoolOptions::RandomKind::Reg,
|
|
"disable-reg-randomization",
|
|
"Disable emission of register randomization code"),
|
|
clEnumValN(firtool::FirtoolOptions::RandomKind::All,
|
|
"disable-all-randomization",
|
|
"Disable emission of all randomization code")),
|
|
llvm::cl::init(firtool::FirtoolOptions::RandomKind::None)};
|
|
|
|
llvm::cl::opt<std::string> outputAnnotationFilename{
|
|
"output-annotation-file",
|
|
llvm::cl::desc("Optional output annotation file"),
|
|
llvm::cl::CommaSeparated, llvm::cl::value_desc("filename")};
|
|
|
|
llvm::cl::opt<bool> enableAnnotationWarning{
|
|
"warn-on-unprocessed-annotations",
|
|
llvm::cl::desc(
|
|
"Warn about annotations that were not removed by lower-to-hw"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> addMuxPragmas{
|
|
"add-mux-pragmas",
|
|
llvm::cl::desc("Annotate mux pragmas for memory array access"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<firrtl::VerificationFlavor> verificationFlavor{
|
|
"verification-flavor",
|
|
llvm::cl::desc("Specify a verification flavor used in LowerFIRRTLToHW"),
|
|
llvm::cl::values(
|
|
clEnumValN(firrtl::VerificationFlavor::None, "none",
|
|
"Use the flavor specified by the op"),
|
|
clEnumValN(firrtl::VerificationFlavor::IfElseFatal, "if-else-fatal",
|
|
"Use Use `if(cond) else $fatal(..)` format"),
|
|
clEnumValN(firrtl::VerificationFlavor::Immediate, "immediate",
|
|
"Use immediate verif statements"),
|
|
clEnumValN(firrtl::VerificationFlavor::SVA, "sva", "Use SVA")),
|
|
llvm::cl::init(firrtl::VerificationFlavor::None)};
|
|
|
|
llvm::cl::opt<bool> emitSeparateAlwaysBlocks{
|
|
"emit-separate-always-blocks",
|
|
llvm::cl::desc(
|
|
"Prevent always blocks from being merged and emit constructs into "
|
|
"separate always blocks whenever possible"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> etcDisableInstanceExtraction{
|
|
"etc-disable-instance-extraction",
|
|
llvm::cl::desc("Disable extracting instances only that feed test code"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> etcDisableRegisterExtraction{
|
|
"etc-disable-register-extraction",
|
|
llvm::cl::desc("Disable extracting registers that only feed test code"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> etcDisableModuleInlining{
|
|
"etc-disable-module-inlining",
|
|
llvm::cl::desc("Disable inlining modules that only feed test code"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> addVivadoRAMAddressConflictSynthesisBugWorkaround{
|
|
"add-vivado-ram-address-conflict-synthesis-bug-workaround",
|
|
llvm::cl::desc(
|
|
"Add a vivado specific SV attribute (* ram_style = "
|
|
"\"distributed\" *) to unpacked array registers as a workaronud "
|
|
"for a vivado synthesis bug that incorrectly modifies "
|
|
"address conflict behavivor of combinational memories"),
|
|
llvm::cl::init(false)};
|
|
|
|
//===----------------------------------------------------------------------===
|
|
// External Clock Gate Options
|
|
//===----------------------------------------------------------------------===
|
|
|
|
llvm::cl::opt<std::string> ckgModuleName{
|
|
"ckg-name", llvm::cl::desc("Clock gate module name"),
|
|
llvm::cl::init("EICG_wrapper")};
|
|
|
|
llvm::cl::opt<std::string> ckgInputName{
|
|
"ckg-input", llvm::cl::desc("Clock gate input port name"),
|
|
llvm::cl::init("in")};
|
|
|
|
llvm::cl::opt<std::string> ckgOutputName{
|
|
"ckg-output", llvm::cl::desc("Clock gate output port name"),
|
|
llvm::cl::init("out")};
|
|
|
|
llvm::cl::opt<std::string> ckgEnableName{
|
|
"ckg-enable", llvm::cl::desc("Clock gate enable port name"),
|
|
llvm::cl::init("en")};
|
|
|
|
llvm::cl::opt<std::string> ckgTestEnableName{
|
|
"ckg-test-enable",
|
|
llvm::cl::desc("Clock gate test enable port name (optional)"),
|
|
llvm::cl::init("test_en")};
|
|
|
|
llvm::cl::opt<bool> exportModuleHierarchy{
|
|
"export-module-hierarchy",
|
|
llvm::cl::desc("Export module and instance hierarchy as JSON"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> stripFirDebugInfo{
|
|
"strip-fir-debug-info",
|
|
llvm::cl::desc(
|
|
"Disable source fir locator information in output Verilog"),
|
|
llvm::cl::init(true)};
|
|
|
|
llvm::cl::opt<bool> stripDebugInfo{
|
|
"strip-debug-info",
|
|
llvm::cl::desc("Disable source locator information in output Verilog"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> fixupEICGWrapper{
|
|
"fixup-eicg-wrapper",
|
|
llvm::cl::desc("Lower `EICG_wrapper` modules into clock gate intrinsics"),
|
|
llvm::cl::init(false)};
|
|
|
|
llvm::cl::opt<bool> addCompanionAssume{
|
|
"add-companion-assume",
|
|
llvm::cl::desc("Add companion assumes to assertions"),
|
|
llvm::cl::init(false)};
|
|
};
|
|
} // namespace
|
|
|
|
static llvm::ManagedStatic<FirtoolCmdOptions> clOptions;
|
|
|
|
/// Register a set of useful command-line options that can be used to configure
|
|
/// various flags within the MLIRContext. These flags are used when constructing
|
|
/// an MLIR context for initialization.
|
|
void circt::firtool::registerFirtoolCLOptions() {
|
|
// Make sure that the options struct has been initialized.
|
|
*clOptions;
|
|
}
|
|
|
|
// Initialize the firtool options with defaults supplied by the cl::opts above.
|
|
circt::firtool::FirtoolOptions::FirtoolOptions()
|
|
: outputFilename("-"), disableAnnotationsUnknown(false),
|
|
disableAnnotationsClassless(false), lowerAnnotationsNoRefTypePorts(false),
|
|
allowAddingPortsOnPublic(false), probesToSignals(false),
|
|
preserveAggregate(firrtl::PreserveAggregate::None),
|
|
preserveMode(firrtl::PreserveValues::None), enableDebugInfo(false),
|
|
buildMode(BuildModeRelease), disableOptimization(false),
|
|
exportChiselInterface(false), chiselInterfaceOutDirectory(""),
|
|
vbToBV(false), noDedup(false), companionMode(firrtl::CompanionMode::Bind),
|
|
disableAggressiveMergeConnections(false), emitOMIR(true), omirOutFile(""),
|
|
lowerMemories(false), blackBoxRootPath(""), replSeqMem(false),
|
|
replSeqMemFile(""), extractTestCode(false), ignoreReadEnableMem(false),
|
|
disableRandom(RandomKind::None), outputAnnotationFilename(""),
|
|
enableAnnotationWarning(false), addMuxPragmas(false),
|
|
verificationFlavor(firrtl::VerificationFlavor::None),
|
|
emitSeparateAlwaysBlocks(false), etcDisableInstanceExtraction(false),
|
|
etcDisableRegisterExtraction(false), etcDisableModuleInlining(false),
|
|
addVivadoRAMAddressConflictSynthesisBugWorkaround(false),
|
|
ckgModuleName("EICG_wrapper"), ckgInputName("in"), ckgOutputName("out"),
|
|
ckgEnableName("en"), ckgTestEnableName("test_en"), ckgInstName("ckg"),
|
|
exportModuleHierarchy(false), stripFirDebugInfo(true),
|
|
stripDebugInfo(false), fixupEICGWrapper(false),
|
|
addCompanionAssume(false) {
|
|
if (!clOptions.isConstructed())
|
|
return;
|
|
outputFilename = clOptions->outputFilename;
|
|
disableAnnotationsUnknown = clOptions->disableAnnotationsUnknown;
|
|
disableAnnotationsClassless = clOptions->disableAnnotationsClassless;
|
|
lowerAnnotationsNoRefTypePorts = clOptions->lowerAnnotationsNoRefTypePorts;
|
|
allowAddingPortsOnPublic = clOptions->allowAddingPortsOnPublic;
|
|
probesToSignals = clOptions->probesToSignals;
|
|
preserveAggregate = clOptions->preserveAggregate;
|
|
preserveMode = clOptions->preserveMode;
|
|
enableDebugInfo = clOptions->enableDebugInfo;
|
|
buildMode = clOptions->buildMode;
|
|
disableOptimization = clOptions->disableOptimization;
|
|
exportChiselInterface = clOptions->exportChiselInterface;
|
|
chiselInterfaceOutDirectory = clOptions->chiselInterfaceOutDirectory;
|
|
vbToBV = clOptions->vbToBV;
|
|
noDedup = clOptions->noDedup;
|
|
companionMode = clOptions->companionMode;
|
|
disableAggressiveMergeConnections =
|
|
clOptions->disableAggressiveMergeConnections;
|
|
emitOMIR = clOptions->emitOMIR;
|
|
omirOutFile = clOptions->omirOutFile;
|
|
lowerMemories = clOptions->lowerMemories;
|
|
blackBoxRootPath = clOptions->blackBoxRootPath;
|
|
replSeqMem = clOptions->replSeqMem;
|
|
replSeqMemFile = clOptions->replSeqMemFile;
|
|
extractTestCode = clOptions->extractTestCode;
|
|
ignoreReadEnableMem = clOptions->ignoreReadEnableMem;
|
|
disableRandom = clOptions->disableRandom;
|
|
outputAnnotationFilename = clOptions->outputAnnotationFilename;
|
|
enableAnnotationWarning = clOptions->enableAnnotationWarning;
|
|
addMuxPragmas = clOptions->addMuxPragmas;
|
|
verificationFlavor = clOptions->verificationFlavor;
|
|
emitSeparateAlwaysBlocks = clOptions->emitSeparateAlwaysBlocks;
|
|
etcDisableInstanceExtraction = clOptions->etcDisableInstanceExtraction;
|
|
etcDisableRegisterExtraction = clOptions->etcDisableRegisterExtraction;
|
|
etcDisableModuleInlining = clOptions->etcDisableModuleInlining;
|
|
addVivadoRAMAddressConflictSynthesisBugWorkaround =
|
|
clOptions->addVivadoRAMAddressConflictSynthesisBugWorkaround;
|
|
ckgModuleName = clOptions->ckgModuleName;
|
|
ckgInputName = clOptions->ckgInputName;
|
|
ckgOutputName = clOptions->ckgOutputName;
|
|
ckgEnableName = clOptions->ckgEnableName;
|
|
ckgTestEnableName = clOptions->ckgTestEnableName;
|
|
exportModuleHierarchy = clOptions->exportModuleHierarchy;
|
|
stripFirDebugInfo = clOptions->stripFirDebugInfo;
|
|
stripDebugInfo = clOptions->stripDebugInfo;
|
|
fixupEICGWrapper = clOptions->fixupEICGWrapper;
|
|
addCompanionAssume = clOptions->addCompanionAssume;
|
|
}
|