28#include "mlir/IR/Attributes.h"
29#include "mlir/Pass/Pass.h"
30#include "mlir/Support/FileUtilities.h"
31#include "llvm/Support/Debug.h"
32#include "llvm/Support/FormatAdapters.h"
33#include "llvm/Support/FormatVariadic.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/Path.h"
37#define DEBUG_TYPE "firrtl-blackbox-reader"
41#define GEN_PASS_DEF_BLACKBOXREADER
42#include "circt/Dialect/FIRRTL/Passes.h.inc"
47using namespace firrtl;
56struct AnnotationInfo {
60 hw::OutputFileAttr outputFileAttr;
62 StringAttr inlineText;
66 void print(raw_ostream &os,
unsigned indent = 0)
const {
67 os << llvm::formatv(
"name: {1}\n"
68 "{0}outputFile: {2}\n"
70 llvm::fmt_pad(
"", indent, 0), name,
71 outputFileAttr.getFilename(),
72 outputFileAttr.getExcludeFromFilelist().getValue());
77struct BlackBoxReaderPass
78 :
public circt::firrtl::impl::BlackBoxReaderBase<BlackBoxReaderPass> {
81 void runOnOperation()
override;
82 bool runOnAnnotation(Operation *op,
Annotation anno, OpBuilder &builder,
83 bool isCover, AnnotationInfo &annotationInfo);
84 StringAttr loadFile(Operation *op, StringRef inputPath, OpBuilder &builder);
85 hw::OutputFileAttr
getOutputFile(Operation *origOp, StringAttr fileNameAttr,
86 bool isCover =
false);
91 SmallVector<emit::FileOp> fileListFiles;
101 StringRef testBenchDir;
109 DenseMap<Operation *, bool> dutModuleMap;
119 llvm::MapVector<StringAttr, AnnotationInfo> emittedFileMap;
124void BlackBoxReaderPass::runOnOperation() {
126 CircuitOp circuitOp = getOperation();
129 instanceGraph = &getAnalysis<InstanceGraph>();
130 instanceInfo = &getAnalysis<InstanceInfo>();
131 auto context = &getContext();
134 bool anythingChanged =
false;
144 SmallVector<Attribute, 4> filteredAnnos;
146 filteredAnnos.push_back(annot.getDict());
150 if (
auto dir = annot.getMember<StringAttr>(
"directory")) {
151 coverDir = dir.getValue();
156 if (
auto dir = annot.getMember<StringAttr>(
"dirname")) {
157 testBenchDir = dir.getValue();
163 if (
auto target = annot.getMember<StringAttr>(
"targetDir")) {
164 targetDir = target.getValue();
168 <<
" annotation missing \"targetDir\" attribute";
178 LLVM_DEBUG(llvm::dbgs() <<
"Black box target directory: " << targetDir
182 auto builder = circuitOp.getBodyBuilder();
184 LLVM_DEBUG(llvm::dbgs() <<
"Visiting extmodules:\n");
186 builder.getDictionaryAttr({{builder.getStringAttr(
"class"),
188 for (
auto extmoduleOp : circuitOp.
getBodyBlock()->getOps<FExtModuleOp>()) {
190 llvm::dbgs().indent(2)
191 <<
"- name: " << extmoduleOp.getModuleNameAttr() <<
"\n";
192 llvm::dbgs().indent(4) <<
"annotations:\n";
197 bool foundBBoxAnno =
false;
198 annotations.removeAnnotations([&](
Annotation anno) {
199 AnnotationInfo annotationInfo;
200 if (!runOnAnnotation(extmoduleOp, anno, builder, isCover, annotationInfo))
203 LLVM_DEBUG(annotationInfo.print(llvm::dbgs().indent(6) <<
"- ", 8));
210 auto [ptr, inserted] =
211 emittedFileMap.try_emplace(annotationInfo.name, annotationInfo);
213 emittedFileMap[annotationInfo.name] = annotationInfo;
215 auto &fileAttr = ptr->second.outputFileAttr;
216 SmallString<64> directory(fileAttr.getDirectory());
218 annotationInfo.outputFileAttr.getDirectory());
219 fileAttr = hw::OutputFileAttr::getFromDirectoryAndFilename(
220 context, directory, annotationInfo.name.getValue(),
222 fileAttr.getExcludeFromFilelist().getValue());
226 foundBBoxAnno =
true;
231 annotations.addAnnotations({bboxAnno});
232 anythingChanged =
true;
234 annotations.applyToOperation(extmoduleOp);
237 LLVM_DEBUG(llvm::dbgs() <<
"emittedFiles:\n");
238 Location loc = builder.getUnknownLoc();
239 for (
auto &[verilogName, annotationInfo] : emittedFileMap) {
241 llvm::dbgs().indent(2) <<
"verilogName: " << verilogName <<
"\n";
242 llvm::dbgs().indent(2) <<
"annotationInfo:\n";
243 annotationInfo.print(llvm::dbgs().indent(4) <<
"- ", 6);
246 auto fileName = ns.newName(
"blackbox_" + verilogName.getValue());
248 auto fileOp = emit::FileOp::create(
249 builder, loc, annotationInfo.outputFileAttr.getFilename(), fileName,
250 [&, text = annotationInfo.inlineText] {
251 emit::VerbatimOp::create(builder, loc, text);
254 if (!annotationInfo.outputFileAttr.getExcludeFromFilelist().getValue())
255 fileListFiles.push_back(fileOp);
261 if (!fileListFiles.empty()) {
263 llvm::sort(fileListFiles.begin(), fileListFiles.end(),
264 [](emit::FileOp fileA, emit::FileOp fileB) {
265 return fileA.getFileName() < fileB.getFileName();
269 SmallVector<Attribute> symbols;
270 for (emit::FileOp file : fileListFiles)
271 symbols.push_back(FlatSymbolRefAttr::
get(file.getSymNameAttr()));
275 if (!anythingChanged)
276 markAllAnalysesPreserved();
277 markAnalysesPreserved<InstanceGraph, InstanceInfo>();
280 emittedFileMap.clear();
281 fileListFiles.clear();
287bool BlackBoxReaderPass::runOnAnnotation(Operation *op,
Annotation anno,
288 OpBuilder &builder,
bool isCover,
289 AnnotationInfo &annotationInfo) {
292 auto name = anno.
getMember<StringAttr>(
"name");
293 auto text = anno.
getMember<StringAttr>(
"text");
294 if (!name || !text) {
296 <<
" annotation missing \"name\" or \"text\" attribute";
301 annotationInfo.outputFileAttr =
getOutputFile(op, name, isCover);
302 annotationInfo.name = name;
303 annotationInfo.inlineText = text;
309 auto path = anno.
getMember<StringAttr>(
"path");
312 <<
" annotation missing \"path\" attribute";
316 SmallString<128> inputPath(inputPrefix);
318 auto text = loadFile(op, inputPath, builder);
320 op->emitError(
"Cannot find file ") << inputPath;
324 auto name = builder.getStringAttr(llvm::sys::path::filename(path));
325 annotationInfo.outputFileAttr =
getOutputFile(op, name, isCover);
326 annotationInfo.name = name;
327 annotationInfo.inlineText = text;
337StringAttr BlackBoxReaderPass::loadFile(Operation *op, StringRef inputPath,
338 OpBuilder &builder) {
339 LLVM_DEBUG(llvm::dbgs() <<
"Add black box source `"
340 << llvm::sys::path::filename(inputPath) <<
"` from `"
341 << inputPath <<
"`\n");
344 std::string errorMessage;
345 auto input = mlir::openInputFile(inputPath, &errorMessage);
350 return builder.getStringAttr(input->getBuffer());
354hw::OutputFileAttr BlackBoxReaderPass::getOutputFile(Operation *origOp,
355 StringAttr fileNameAttr,
359 auto outputFile = origOp->getAttrOfType<hw::OutputFileAttr>(
"output_file");
360 if (outputFile && !outputFile.isDirectory()) {
366 auto *context = &getContext();
367 auto fileName = fileNameAttr.getValue();
368 auto ext = llvm::sys::path::extension(fileName);
369 bool exclude = (ext ==
".h" || ext ==
".vh" || ext ==
".svh");
370 auto outDir = targetDir;
374 outDir = outputFile.getFilename();
379 else if (!testBenchDir.empty() && targetDir ==
"." &&
380 !instanceInfo->anyInstanceInEffectiveDesign(
381 cast<igraph::ModuleOpInterface>(origOp)))
382 outDir = testBenchDir;
388 SmallString<128> outputFilePath(outDir);
389 llvm::sys::path::append(outputFilePath, fileName);
390 return hw::OutputFileAttr::getFromFilename(context, outputFilePath, exclude);
static OutputFileAttr getOutputFile(igraph::ModuleOpInterface op)
static void print(TypedAttr val, llvm::raw_ostream &os)
static Block * getBodyBlock(FModuleLike mod)
#define CIRCT_DEBUG_SCOPED_PASS_LOGGER(PASS)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
This class provides a read-only projection of an annotation.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
This graph tracks modules and where they are instantiated.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
constexpr const char * extractCoverageAnnoClass
constexpr const char * blackBoxAnnoClass
constexpr const char * testBenchDirAnnoClass
constexpr const char * verifBlackBoxAnnoClass
constexpr const char * blackBoxPathAnnoClass
constexpr const char * blackBoxTargetDirAnnoClass
constexpr const char * blackBoxInlineAnnoClass
void makeCommonPrefix(SmallString< 64 > &a, StringRef b)
Truncate a to the common prefix of a and b.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void appendPossiblyAbsolutePath(llvm::SmallVectorImpl< char > &base, const llvm::Twine &suffix)
Append a path to an existing path, replacing it if the other path is absolute.
The namespace of a CircuitOp, generally inhabited by modules.