25#include "mlir/IR/ImplicitLocOpBuilder.h"
26#include "mlir/IR/Location.h"
27#include "mlir/Pass/Pass.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/StringSwitch.h"
30#include "llvm/Support/JSON.h"
31#include "llvm/Support/Path.h"
35#define GEN_PASS_DEF_CREATESIFIVEMETADATA
36#include "circt/Dialect/FIRRTL/Passes.h.inc"
41using namespace firrtl;
49 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces)
50 : context(circtOp->getContext()), circtOp(circtOp),
53 instanceInfo(instanceInfo), moduleNamespaces(moduleNamespaces) {}
57 mlir::ImplicitLocOpBuilder &builderOM) {
59 auto id = DistinctAttr::create(UnitAttr::get(context));
60 TargetKind kind = TargetKind::Reference;
64 fields.append(
"id",
id);
65 fields.append(
"class", StringAttr::get(context,
"circt.tracker"));
67 fields.append(
"circt.nonlocal", mlir::FlatSymbolRefAttr::get(nla));
69 annos.addAnnotations(DictionaryAttr::get(context, fields));
70 annos.applyToOperation(op);
71 if (isa<InstanceOp, FModuleLike>(op))
72 kind = TargetKind::Instance;
76 return builderOM.create<PathOp>(kind, id);
79 void createMemorySchema() {
81 auto unknownLoc = mlir::UnknownLoc::get(context);
82 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
83 unknownLoc, circtOp.getBodyBlock());
88 mlir::Type extraPortsType[] = {
89 StringType::get(context),
90 StringType::get(context),
91 FIntegerType::get(context)
93 StringRef extraPortFields[3] = {
"name",
"direction",
"width"};
95 extraPortsClass = builderOM.create<ClassOp>(
96 "ExtraPortsMemorySchema", extraPortFields, extraPortsType);
98 mlir::Type classFieldTypes[13] = {
99 StringType::get(context),
100 FIntegerType::get(context),
101 FIntegerType::get(context),
102 FIntegerType::get(context),
103 FIntegerType::get(context),
104 FIntegerType::get(context),
105 FIntegerType::get(context),
106 FIntegerType::get(context),
107 FIntegerType::get(context),
108 ListType::get(context, cast<PropertyType>(PathType::get(context))),
109 BoolType::get(context),
111 context, cast<PropertyType>(
112 detail::getInstanceTypeForClassLike(extraPortsClass))),
113 ListType::get(context, cast<PropertyType>(StringType::get(context))),
116 memorySchemaClass = builderOM.create<ClassOp>(
117 "MemorySchema", memoryParamNames, classFieldTypes);
121 SmallVector<PortInfo> mports;
122 memoryMetadataClass = builderOM.create<ClassOp>(
123 builderOM.getStringAttr(
"MemoryMetadata"), mports);
126 void createRetimeModulesSchema() {
127 auto unknownLoc = mlir::UnknownLoc::get(context);
128 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
129 unknownLoc, circtOp.getBodyBlock());
130 Type classFieldTypes[] = {StringType::get(context)};
131 retimeModulesSchemaClass = builderOM.create<ClassOp>(
132 "RetimeModulesSchema", retimeModulesParamNames, classFieldTypes);
134 SmallVector<PortInfo> mports;
135 retimeModulesMetadataClass = builderOM.create<ClassOp>(
136 builderOM.getStringAttr(
"RetimeModulesMetadata"), mports);
139 void addRetimeModule(FModuleLike module) {
140 if (!retimeModulesSchemaClass)
141 createRetimeModulesSchema();
142 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
143 module->getLoc(), retimeModulesMetadataClass.getBodyBlock());
147 builderOM.create<StringConstantOp>(
module.getModuleNameAttr());
148 auto object = builderOM.create<ObjectOp>(retimeModulesSchemaClass,
149 module.getModuleNameAttr());
151 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
152 builderOM.create<PropAssignOp>(inPort, modEntry);
153 auto portIndex = retimeModulesMetadataClass.getNumPorts();
154 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
156 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
157 object.getType(), Direction::Out)}};
158 retimeModulesMetadataClass.insertPorts(newPorts);
159 auto blockarg = retimeModulesMetadataClass.getBodyBlock()->addArgument(
160 object.getType(), module->getLoc());
161 builderOM.create<PropAssignOp>(blockarg, object);
164 void addBlackBoxModulesSchema() {
165 auto unknownLoc = mlir::UnknownLoc::get(context);
166 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
167 unknownLoc, circtOp.getBodyBlock());
168 Type classFieldTypes[] = {StringType::get(context), BoolType::get(context)};
169 blackBoxModulesSchemaClass =
170 builderOM.create<ClassOp>(
"SitestBlackBoxModulesSchema",
171 blackBoxModulesParamNames, classFieldTypes);
172 SmallVector<PortInfo> mports;
173 blackBoxMetadataClass = builderOM.create<ClassOp>(
174 builderOM.getStringAttr(
"SitestBlackBoxMetadata"), mports);
177 void addBlackBoxModule(FExtModuleOp module,
bool inDut) {
178 if (!blackBoxModulesSchemaClass)
179 addBlackBoxModulesSchema();
180 StringRef defName = *
module.getDefname();
181 if (!blackboxModules.insert(defName).second)
183 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
184 module.getLoc(), blackBoxMetadataClass.getBodyBlock());
185 auto modEntry = builderOM.create<StringConstantOp>(
module.getDefnameAttr());
186 auto inDutAttr = builderOM.create<BoolConstantOp>(inDut);
187 auto object = builderOM.create<ObjectOp>(blackBoxModulesSchemaClass,
188 module.getModuleNameAttr());
190 auto inPortModuleName = builderOM.create<ObjectSubfieldOp>(object, 0);
191 builderOM.create<PropAssignOp>(inPortModuleName, modEntry);
192 auto inPortInDut = builderOM.create<ObjectSubfieldOp>(object, 2);
193 builderOM.create<PropAssignOp>(inPortInDut, inDutAttr);
194 auto portIndex = blackBoxMetadataClass.getNumPorts();
195 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
197 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
198 object.getType(), Direction::Out)}};
199 blackBoxMetadataClass.insertPorts(newPorts);
200 auto blockarg = blackBoxMetadataClass.getBodyBlock()->addArgument(
201 object.getType(), module->getLoc());
202 builderOM.create<PropAssignOp>(blockarg, object);
205 void addMemory(FMemModuleOp mem) {
206 if (!memorySchemaClass)
207 createMemorySchema();
208 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
209 mem.getLoc(), memoryMetadataClass.getBodyBlock());
210 auto createConstField = [&](Attribute constVal) -> Value {
211 if (
auto boolConstant = dyn_cast_or_null<mlir::BoolAttr>(constVal))
212 return builderOM.create<BoolConstantOp>(boolConstant);
213 if (
auto intConstant = dyn_cast_or_null<mlir::IntegerAttr>(constVal))
214 return builderOM.create<FIntegerConstantOp>(intConstant);
215 if (
auto strConstant = dyn_cast_or_null<mlir::StringAttr>(constVal))
216 return builderOM.create<StringConstantOp>(strConstant);
219 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
221 auto memPaths = instancePathCache.getAbsolutePaths(mem);
222 SmallVector<Value> memoryHierPaths;
223 SmallVector<Value> finalInstanceNames;
236 for (
auto memPath : memPaths) {
238 igraph::InstanceOpInterface finalInst = memPath.leaf();
239 finalInstanceNames.emplace_back(builderOM.create<StringConstantOp>(
240 finalInst.getInstanceNameAttr()));
242 SmallVector<Attribute> namepath;
243 bool foundDut =
false;
247 igraph::InstanceOpInterface preExtractedLeafInstance;
248 for (
auto inst :
llvm::drop_end(memPath)) {
251 inst->getParentOfType<FModuleOp>()))
257 if (inst->getParentOfType<LayerBlockOp>()) {
264 return getModuleNamespace(mod);
266 preExtractedLeafInstance = inst;
269 if (!namepath.empty()) {
271 auto nla = nlaBuilder.create<hw::HierPathOp>(
273 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
274 nlaBuilder.getArrayAttr(namepath));
275 nla.setVisibility(SymbolTable::Visibility::Private);
276 pathRef =
createPathRef(preExtractedLeafInstance, nla, builderOM);
285 memoryHierPaths.push_back(pathRef);
288 auto finalInstNamesList = builderOM.create<ListCreateOp>(
289 ListType::get(context, cast<PropertyType>(StringType::get(context))),
291 auto hierpaths = builderOM.create<ListCreateOp>(
292 ListType::get(context, cast<PropertyType>(PathType::get(context))),
294 SmallVector<Value> memFields;
296 auto object = builderOM.create<ObjectOp>(memorySchemaClass, mem.getName());
297 SmallVector<Value> extraPortsList;
298 ClassType extraPortsType;
299 for (
auto attr : mem.getExtraPortsAttr()) {
301 auto port = cast<DictionaryAttr>(attr);
302 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
303 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
304 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
306 builderOM.create<ObjectOp>(extraPortsClass,
"extraPorts");
307 extraPortsType = extraPortsObj.getType();
308 auto inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 0);
309 builderOM.create<PropAssignOp>(inPort, portName);
310 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 2);
311 builderOM.create<PropAssignOp>(inPort, direction);
312 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 4);
313 builderOM.create<PropAssignOp>(inPort, width);
314 extraPortsList.push_back(extraPortsObj);
316 auto extraPorts = builderOM.create<ListCreateOp>(
317 memorySchemaClass.getPortType(22), extraPortsList);
318 for (
auto field :
llvm::enumerate(memoryParamNames)) {
319 auto propVal = createConstField(
320 llvm::StringSwitch<TypedAttr>(field.value())
321 .Case(
"name", builderOM.getStringAttr(mem.getName()))
322 .Case(
"depth", mem.getDepthAttr())
323 .Case(
"width", mem.getDataWidthAttr())
324 .Case(
"maskBits", mem.getMaskBitsAttr())
325 .Case(
"readPorts", mem.getNumReadPortsAttr())
326 .Case(
"writePorts", mem.getNumWritePortsAttr())
327 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
328 .Case(
"readLatency", mem.getReadLatencyAttr())
329 .Case(
"writeLatency", mem.getWriteLatencyAttr())
330 .Case(
"hierarchy", {})
331 .Case(
"inDut", BoolAttr::get(context, inDut))
332 .Case(
"extraPorts", {})
333 .Case(
"preExtInstName", {}));
335 if (field.value() ==
"hierarchy")
337 else if (field.value() ==
"preExtInstName")
338 propVal = finalInstNamesList;
340 propVal = extraPorts;
349 builderOM.create<ObjectSubfieldOp>(object, 2 * field.index());
350 builderOM.create<PropAssignOp>(inPort, propVal);
352 auto portIndex = memoryMetadataClass.getNumPorts();
353 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
354 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
355 object.getType(), Direction::Out)}};
356 memoryMetadataClass.insertPorts(newPorts);
357 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
358 object.getType(), mem->getLoc());
359 builderOM.create<PropAssignOp>(blockarg, object);
362 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
363 if (!blackBoxMetadataClass && !memoryMetadataClass &&
364 !retimeModulesMetadataClass && !instanceInfo.
hasDut())
366 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
367 mlir::UnknownLoc::get(circtOp->getContext()), circtOp.getBodyBlock());
368 SmallVector<PortInfo> mports;
369 auto sifiveMetadataClass = builder.create<ClassOp>(
370 builder.getStringAttr(
"SiFive_Metadata"), mports);
371 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
373 auto addPort = [&](Value obj, StringRef fieldName) {
374 auto portIndex = sifiveMetadataClass.getNumPorts();
375 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
376 {portIndex,
PortInfo(builder.getStringAttr(fieldName +
"_field_" +
378 obj.getType(), Direction::Out)}};
379 sifiveMetadataClass.insertPorts(newPorts);
380 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
381 obj.getType(), topMod->getLoc());
382 builder.create<PropAssignOp>(blockarg, obj);
384 if (blackBoxMetadataClass)
386 builder.create<ObjectOp>(blackBoxMetadataClass,
387 builder.getStringAttr(
"blackbox_metadata")),
390 if (memoryMetadataClass)
392 builder.create<ObjectOp>(memoryMetadataClass,
393 builder.getStringAttr(
"memory_metadata")),
396 if (retimeModulesMetadataClass)
397 addPort(builder.create<ObjectOp>(
398 retimeModulesMetadataClass,
399 builder.getStringAttr(
"retime_modules_metadata")),
402 if (instanceInfo.
hasDut()) {
403 auto dutMod = instanceInfo.
getDut();
407 SmallVector<Value, 2> pathOpsToDut;
409 auto dutPaths = instancePathCache.getAbsolutePaths(dutMod);
411 for (
auto dutPath : dutPaths) {
412 SmallVector<Attribute> namepath;
414 for (
auto inst : dutPath)
417 return getModuleNamespace(mod);
419 if (namepath.empty())
423 auto leafInst = dutPath.leaf();
424 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
425 auto nla = nlaBuilder.create<hw::HierPathOp>(
427 nlaBuilder.getStringAttr(circtNamespace.newName(
"dutNLA")),
428 nlaBuilder.getArrayAttr(namepath));
429 nla.setVisibility(SymbolTable::Visibility::Private);
431 pathOpsToDut.emplace_back(
createPathRef(leafInst, nla, builder));
434 auto pathList = builder.create<ListCreateOp>(
435 ListType::get(context, cast<PropertyType>(PathType::get(context))),
437 addPort(pathList,
"dutModulePath");
440 builder.setInsertionPointToEnd(topMod.getBodyBlock());
441 return builder.create<ObjectOp>(sifiveMetadataClass,
442 builder.getStringAttr(
"sifive_metadata"));
447 return moduleNamespaces.try_emplace(module, module).first->second;
449 MLIRContext *context;
455 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
456 ClassOp memorySchemaClass, extraPortsClass;
457 ClassOp memoryMetadataClass;
458 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
459 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
460 StringRef memoryParamNames[13] = {
461 "name",
"depth",
"width",
"maskBits",
462 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
463 "readLatency",
"hierarchy",
"inDut",
"extraPorts",
465 StringRef retimeModulesParamNames[1] = {
"moduleName"};
466 StringRef blackBoxModulesParamNames[2] = {
"moduleName",
"inDut"};
467 llvm::SmallDenseSet<StringRef> blackboxModules;
470class CreateSiFiveMetadataPass
471 :
public circt::firrtl::impl::CreateSiFiveMetadataBase<
472 CreateSiFiveMetadataPass> {
473 LogicalResult emitRetimeModulesMetadata(ObjectModelIR &omir);
474 LogicalResult emitSitestBlackboxMetadata(ObjectModelIR &omir);
475 LogicalResult emitMemoryMetadata(ObjectModelIR &omir);
476 void runOnOperation()
override;
480 return moduleNamespaces.try_emplace(module, module).first->second;
483 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
489 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
490 this->replSeqMem = replSeqMem;
491 this->replSeqMemFile = replSeqMemFile.str();
499CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
504 auto addSymbolToVerbatimOp =
506 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
508 if (
auto module = dyn_cast<FModuleLike>(op))
509 symbol = FlatSymbolRefAttr::get(module);
513 return getModuleNamespace(mod);
516 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
518 symbols.push_back(symbol);
521 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
527 auto createMemMetadata = [&](FMemModuleOp mem,
528 llvm::json::OStream &jsonStream,
529 std::string &seqMemConfStr,
530 SmallVectorImpl<Attribute> &jsonSymbols,
531 SmallVectorImpl<Attribute> &seqMemSymbols) {
534 auto width = mem.getDataWidth();
539 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 || width <= 0)
541 auto memExtSym = FlatSymbolRefAttr::get(SymbolTable::getSymbolName(mem));
542 auto symId = seqMemSymbols.size();
543 seqMemSymbols.push_back(memExtSym);
545 auto isMasked = mem.isMasked();
546 auto maskGran = width;
548 maskGran /= mem.getMaskBits();
551 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
552 if (!portStr.empty())
554 portStr += isMasked ?
"mwrite" :
"write";
556 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
557 if (!portStr.empty())
561 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
562 if (!portStr.empty())
564 portStr += isMasked ?
"mrw" :
"rw";
568 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
569 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
570 "}} depth " + Twine(mem.getDepth()) +
" width " +
571 Twine(width) +
" ports " + portStr + maskGranStr +
"\n")
578 jsonStream.object([&] {
579 jsonStream.attribute(
"module_name",
580 addSymbolToVerbatimOp(mem, jsonSymbols));
581 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
582 jsonStream.attribute(
"width", (int64_t)width);
583 jsonStream.attribute(
"masked", isMasked);
584 jsonStream.attribute(
"read", mem.getNumReadPorts());
585 jsonStream.attribute(
"write", mem.getNumWritePorts());
586 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
588 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
589 jsonStream.attributeArray(
"extra_ports", [&] {
590 for (
auto attr : mem.getExtraPorts()) {
591 jsonStream.object([&] {
592 auto port = cast<DictionaryAttr>(attr);
593 auto name = port.getAs<StringAttr>(
"name").getValue();
594 jsonStream.attribute(
"name", name);
595 auto direction = port.getAs<StringAttr>(
"direction").getValue();
596 jsonStream.attribute(
"direction", direction);
597 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
598 jsonStream.attribute(
"width", width);
603 jsonStream.attributeArray(
"hierarchy", [&] {
606 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
607 for (
auto p : paths) {
615 bool inDut =
false, underLayer =
false;
616 for (
auto inst : p) {
617 auto parent = inst->getParentOfType<FModuleOp>();
618 inDut |= parent == dutMod;
619 if (inst->getParentOfType<LayerBlockOp>())
622 if (!inDut || underLayer)
626 std::string hierName =
627 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
630 auto finalInst = p.leaf();
631 for (
auto inst :
llvm::drop_end(p)) {
632 auto parentModule = inst->getParentOfType<FModuleOp>();
633 if (instanceInfo->
getDut() == parentModule)
635 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
637 hierName = hierName +
"." +
638 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
640 hierName += (
"." + finalInst.getInstanceName()).str();
642 jsonStream.value(hierName);
648 std::string dutJsonBuffer;
649 llvm::raw_string_ostream dutOs(dutJsonBuffer);
650 llvm::json::OStream dutJson(dutOs, 2);
651 SmallVector<Attribute, 8> seqMemSymbols;
652 SmallVector<Attribute, 8> jsonSymbols;
654 std::string seqMemConfStr;
656 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
657 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
661 auto *context = &getContext();
662 auto builder = ImplicitLocOpBuilder::atBlockEnd(UnknownLoc::get(context),
663 circuitOp.getBodyBlock());
666 StringRef metadataDir =
"metadata";
668 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
669 metadataDir = dir.getValue();
673 SmallString<128> seqMemsJsonPath(metadataDir);
674 llvm::sys::path::append(seqMemsJsonPath,
"seq_mems.json");
675 builder.create<emit::FileOp>(seqMemsJsonPath, [&] {
676 builder.create<sv::VerbatimOp>(dutJsonBuffer, ValueRange{},
677 builder.getArrayAttr(jsonSymbols));
682 if (replSeqMemFile.empty()) {
683 emitError(circuitOp->getLoc())
684 <<
"metadata emission failed, the option "
685 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
686 "valid seq mem metadata file";
690 builder.create<emit::FileOp>(replSeqMemFile, [&] {
691 builder.create<sv::VerbatimOp>(seqMemConfStr, ValueRange{},
692 builder.getArrayAttr(seqMemSymbols));
706 StringRef &filename) {
711 if (error || !anno.
isClass(annoClass))
715 if (!filename.empty()) {
716 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
722 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
724 op->emitError(annoClass) <<
" requires a filename";
730 filename = filenameAttr.getValue();
731 if (filename.empty()) {
732 op->emitError(annoClass) <<
" requires a non-empty filename";
741 return failure(error);
747CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
749 auto *context = &getContext();
757 if (filename.empty())
762 llvm::raw_string_ostream os(buffer);
763 llvm::json::OStream j(os, 2);
767 SmallVector<Attribute> symbols;
768 SmallString<3> placeholder;
770 for (
auto module : circuitOp.
getBodyBlock()->getOps<FModuleLike>()) {
778 j.value((
"{{" + Twine(index++) +
"}}").str());
779 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
780 omir.addRetimeModule(module);
785 auto builder = ImplicitLocOpBuilder::atBlockEnd(UnknownLoc::get(context),
786 circuitOp.getBodyBlock());
787 builder.create<emit::FileOp>(filename, [&] {
788 builder.create<sv::VerbatimOp>(builder.getStringAttr(buffer), ValueRange{},
789 builder.getArrayAttr(symbols));
797CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
801 std::array<StringRef, 6> blackListedAnnos = {
805 auto *context = &getContext();
808 StringRef dutFilename, testFilename;
816 if (dutFilename.empty() && testFilename.empty())
822 SmallVector<StringRef> dutModules;
823 SmallVector<StringRef> testModules;
824 for (
auto extModule : circuitOp.
getBodyBlock()->getOps<FExtModuleOp>()) {
827 if (!extModule.getDefname())
832 if (llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
833 return annos.hasAnnotation(blackListedAnno);
841 dutModules.push_back(*extModule.getDefname());
843 testModules.push_back(*extModule.getDefname());
845 omir.addBlackBoxModule(extModule, inDut);
849 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
850 StringRef filename) {
851 if (filename.empty())
855 std::sort(names.begin(), names.end());
856 names.erase(std::unique(names.begin(), names.end()), names.end());
861 llvm::raw_string_ostream os(buffer);
862 llvm::json::OStream j(os, 2);
864 for (
auto &name : names)
869 auto builder = ImplicitLocOpBuilder::atBlockEnd(UnknownLoc::get(context),
870 circuitOp.getBodyBlock());
872 builder.create<emit::FileOp>(filename, [&] {
873 builder.create<emit::VerbatimOp>(StringAttr::get(context, buffer));
877 createOutput(testModules, testFilename);
878 createOutput(dutModules, dutFilename);
883void CreateSiFiveMetadataPass::runOnOperation() {
884 auto circuits = getOperation().getOps<CircuitOp>();
885 if (circuits.empty())
888 circuitOp = *circuits.begin();
890 if (!llvm::hasSingleElement(circuits)) {
891 mlir::emitError(circuitOp.getLoc(),
892 "cannot process multiple circuit operations")
893 .attachNote((*std::next(circuits.begin())).getLoc())
894 <<
"second circuit here";
895 return signalPassFailure();
898 auto &instanceGraph = getAnalysis<InstanceGraph>();
899 instanceInfo = &getAnalysis<InstanceInfo>();
900 ObjectModelIR omir(circuitOp, instanceGraph, *instanceInfo, moduleNamespaces);
902 if (failed(emitRetimeModulesMetadata(omir)) ||
903 failed(emitSitestBlackboxMetadata(omir)) ||
904 failed(emitMemoryMetadata(omir)))
905 return signalPassFailure();
907 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->getModule()))
908 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
909 auto portIndex = topMod.getNumPorts();
910 SmallVector<std::pair<unsigned, PortInfo>> ports = {
912 PortInfo(StringAttr::get(objectOp->getContext(),
"metadataObj"),
913 AnyRefType::get(objectOp->getContext()), Direction::Out)}};
914 topMod.insertPorts(ports);
915 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
916 topMod->getLoc(), topMod.getBodyBlock());
917 auto objectCast = builderOM.create<ObjectAnyRefCastOp>(objectOp);
918 builderOM.create<PropAssignOp>(topMod.getArgument(portIndex), objectCast);
928std::unique_ptr<mlir::Pass>
930 StringRef replSeqMemFile) {
931 return std::make_unique<CreateSiFiveMetadataPass>(replSeqMem, replSeqMemFile);
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Block * getBodyBlock(FModuleLike mod)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
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.
igraph::InstanceGraphNode * getTopLevelNode() override
Get the node corresponding to the top-level module of a circuit.
igraph::ModuleOpInterface getDut()
Return the design-under-test if one is defined for the circuit, otherwise return null.
bool isEffectiveDut(igraph::ModuleOpInterface op)
Return true if this module is the design-under-test and the circuit has a design-under-test.
bool hasDut()
Return true if this circuit has a design-under-test.
igraph::ModuleOpInterface getEffectiveDut()
Return the "effective" design-under-test.
bool anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) the effective design.
igraph::InstancePathCache InstancePathCache
constexpr const char * blackBoxAnnoClass
constexpr const char * sitestBlackBoxAnnoClass
constexpr const char * metadataDirectoryAttrName
constexpr const char * sitestTestHarnessBlackBoxAnnoClass
PathOp createPathRef(Operation *op, hw::HierPathOp nla, mlir::ImplicitLocOpBuilder &builderOM)
Add the tracker annotation to the op and get a PathOp to the op.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
constexpr const char * dataTapsBlackboxClass
constexpr const char * memTapBlackboxClass
constexpr const char * blackBoxPathAnnoClass
constexpr const char * retimeModulesFileAnnoClass
constexpr const char * retimeModuleAnnoClass
std::unique_ptr< mlir::Pass > createCreateSiFiveMetadataPass(bool replSeqMem=false, mlir::StringRef replSeqMemFile="")
constexpr const char * blackBoxInlineAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The namespace of a CircuitOp, generally inhabited by modules.
This holds the name and type that describes the module's ports.
A data structure that caches and provides absolute paths to module instances in the IR.