25 #include "mlir/IR/ImplicitLocOpBuilder.h"
26 #include "mlir/IR/Location.h"
27 #include "mlir/Pass/Pass.h"
28 #include "llvm/ADT/DepthFirstIterator.h"
29 #include "llvm/ADT/STLExtras.h"
30 #include "llvm/ADT/StringSwitch.h"
31 #include "llvm/Support/JSON.h"
32 #include "llvm/Support/Path.h"
36 #define GEN_PASS_DEF_CREATESIFIVEMETADATA
37 #include "circt/Dialect/FIRRTL/Passes.h.inc"
41 using namespace circt;
42 using namespace firrtl;
46 struct ObjectModelIR {
50 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces)
51 : context(circtOp->getContext()), circtOp(circtOp),
54 instanceInfo(instanceInfo), moduleNamespaces(moduleNamespaces) {}
58 mlir::ImplicitLocOpBuilder &builderOM) {
61 TargetKind kind = TargetKind::Reference;
65 fields.append(
"id",
id);
71 annos.applyToOperation(op);
72 if (isa<InstanceOp, FModuleLike>(op))
73 kind = TargetKind::Instance;
77 return builderOM.create<PathOp>(kind, id);
80 void createMemorySchema() {
83 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
84 unknownLoc, circtOp.getBodyBlock());
89 mlir::Type extraPortsType[] = {
94 StringRef extraPortFields[3] = {
"name",
"direction",
"width"};
96 extraPortsClass = builderOM.create<ClassOp>(
97 "ExtraPortsMemorySchema", extraPortFields, extraPortsType);
99 mlir::Type classFieldTypes[13] = {
112 context, cast<PropertyType>(
117 memorySchemaClass = builderOM.create<ClassOp>(
118 "MemorySchema", memoryParamNames, classFieldTypes);
122 SmallVector<PortInfo> mports;
123 memoryMetadataClass = builderOM.create<ClassOp>(
124 builderOM.getStringAttr(
"MemoryMetadata"), mports);
127 void createRetimeModulesSchema() {
129 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
130 unknownLoc, circtOp.getBodyBlock());
132 retimeModulesSchemaClass = builderOM.create<ClassOp>(
133 "RetimeModulesSchema", retimeModulesParamNames, classFieldTypes);
135 SmallVector<PortInfo> mports;
136 retimeModulesMetadataClass = builderOM.create<ClassOp>(
137 builderOM.getStringAttr(
"RetimeModulesMetadata"), mports);
140 void addRetimeModule(FModuleLike module) {
141 if (!retimeModulesSchemaClass)
142 createRetimeModulesSchema();
143 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
144 module->getLoc(), retimeModulesMetadataClass.getBodyBlock());
148 builderOM.create<StringConstantOp>(module.getModuleNameAttr());
149 auto object = builderOM.create<ObjectOp>(retimeModulesSchemaClass,
150 module.getModuleNameAttr());
152 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
153 builderOM.create<PropAssignOp>(inPort, modEntry);
154 auto portIndex = retimeModulesMetadataClass.getNumPorts();
155 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
157 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
159 retimeModulesMetadataClass.insertPorts(newPorts);
160 auto blockarg = retimeModulesMetadataClass.getBodyBlock()->addArgument(
161 object.getType(), module->getLoc());
162 builderOM.create<PropAssignOp>(blockarg, object);
165 void addBlackBoxModulesSchema() {
167 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
168 unknownLoc, circtOp.getBodyBlock());
170 blackBoxModulesSchemaClass =
171 builderOM.create<ClassOp>(
"SitestBlackBoxModulesSchema",
172 blackBoxModulesParamNames, classFieldTypes);
173 SmallVector<PortInfo> mports;
174 blackBoxMetadataClass = builderOM.create<ClassOp>(
175 builderOM.getStringAttr(
"SitestBlackBoxMetadata"), mports);
178 void addBlackBoxModule(FExtModuleOp module) {
179 if (!blackBoxModulesSchemaClass)
180 addBlackBoxModulesSchema();
181 StringRef defName = *module.getDefname();
182 if (!blackboxModules.insert(defName).second)
184 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
185 module.getLoc(), blackBoxMetadataClass.getBodyBlock());
186 auto modEntry = builderOM.create<StringConstantOp>(module.getDefnameAttr());
187 auto object = builderOM.create<ObjectOp>(blackBoxModulesSchemaClass,
188 module.getModuleNameAttr());
190 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
191 builderOM.create<PropAssignOp>(inPort, modEntry);
192 auto portIndex = blackBoxMetadataClass.getNumPorts();
193 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
195 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
197 blackBoxMetadataClass.insertPorts(newPorts);
198 auto blockarg = blackBoxMetadataClass.getBodyBlock()->addArgument(
199 object.getType(), module->getLoc());
200 builderOM.create<PropAssignOp>(blockarg, object);
203 void addMemory(FMemModuleOp mem) {
204 if (!memorySchemaClass)
205 createMemorySchema();
206 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
207 mem.getLoc(), memoryMetadataClass.getBodyBlock());
208 auto createConstField = [&](Attribute constVal) -> Value {
209 if (
auto boolConstant = dyn_cast_or_null<mlir::BoolAttr>(constVal))
210 return builderOM.create<BoolConstantOp>(boolConstant);
211 if (
auto intConstant = dyn_cast_or_null<mlir::IntegerAttr>(constVal))
212 return builderOM.create<FIntegerConstantOp>(intConstant);
213 if (
auto strConstant = dyn_cast_or_null<mlir::StringAttr>(constVal))
214 return builderOM.create<StringConstantOp>(strConstant);
217 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
219 auto memPaths = instancePathCache.getAbsolutePaths(mem);
220 SmallVector<Value> memoryHierPaths;
221 SmallVector<Value> finalInstanceNames;
225 for (
auto memPath : memPaths) {
227 igraph::InstanceOpInterface finalInst = memPath.leaf();
228 finalInstanceNames.emplace_back(builderOM.create<StringConstantOp>(
229 finalInst.getInstanceNameAttr()));
231 SmallVector<Attribute> namepath;
232 bool foundDut =
false;
236 igraph::InstanceOpInterface preExtractedLeafInstance;
237 for (
auto inst : llvm::drop_end(memPath)) {
240 inst->getParentOfType<FModuleOp>()))
246 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
247 return getModuleNamespace(mod);
249 preExtractedLeafInstance = inst;
252 if (!namepath.empty()) {
253 auto nla = nlaBuilder.create<hw::HierPathOp>(
255 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
256 nlaBuilder.getArrayAttr(namepath));
257 pathRef =
createPathRef(preExtractedLeafInstance, nla, builderOM);
263 memoryHierPaths.push_back(pathRef);
266 auto finalInstNamesList = builderOM.create<ListCreateOp>(
269 auto hierpaths = builderOM.create<ListCreateOp>(
272 SmallVector<Value> memFields;
274 auto object = builderOM.create<ObjectOp>(memorySchemaClass, mem.getName());
275 SmallVector<Value> extraPortsList;
276 ClassType extraPortsType;
277 for (
auto attr : mem.getExtraPortsAttr()) {
279 auto port = cast<DictionaryAttr>(attr);
280 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
281 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
282 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
284 builderOM.create<ObjectOp>(extraPortsClass,
"extraPorts");
285 extraPortsType = extraPortsObj.getType();
286 auto inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 0);
287 builderOM.create<PropAssignOp>(inPort, portName);
288 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 2);
289 builderOM.create<PropAssignOp>(inPort, direction);
290 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 4);
291 builderOM.create<PropAssignOp>(inPort,
width);
292 extraPortsList.push_back(extraPortsObj);
294 auto extraPorts = builderOM.create<ListCreateOp>(
295 memorySchemaClass.getPortType(22), extraPortsList);
296 for (
auto field : llvm::enumerate(memoryParamNames)) {
297 auto propVal = createConstField(
298 llvm::StringSwitch<TypedAttr>(field.value())
299 .Case(
"name", builderOM.getStringAttr(mem.getName()))
300 .Case(
"depth", mem.getDepthAttr())
301 .Case(
"width", mem.getDataWidthAttr())
302 .Case(
"maskBits", mem.getMaskBitsAttr())
303 .Case(
"readPorts", mem.getNumReadPortsAttr())
304 .Case(
"writePorts", mem.getNumWritePortsAttr())
305 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
306 .Case(
"readLatency", mem.getReadLatencyAttr())
307 .Case(
"writeLatency", mem.getWriteLatencyAttr())
308 .Case(
"hierarchy", {})
310 .Case(
"extraPorts", {})
311 .Case(
"preExtInstName", {}));
313 if (field.value() ==
"hierarchy")
315 else if (field.value() ==
"preExtInstName")
316 propVal = finalInstNamesList;
318 propVal = extraPorts;
327 builderOM.create<ObjectSubfieldOp>(object, 2 * field.index());
328 builderOM.create<PropAssignOp>(inPort, propVal);
330 auto portIndex = memoryMetadataClass.getNumPorts();
331 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
332 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
334 memoryMetadataClass.insertPorts(newPorts);
335 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
336 object.getType(), mem->getLoc());
337 builderOM.create<PropAssignOp>(blockarg, object);
340 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
341 if (!blackBoxMetadataClass && !memoryMetadataClass &&
342 !retimeModulesMetadataClass)
344 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
346 SmallVector<PortInfo> mports;
347 auto sifiveMetadataClass = builder.create<ClassOp>(
348 builder.getStringAttr(
"SiFive_Metadata"), mports);
349 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
351 auto addPort = [&](Value obj, StringRef fieldName) {
352 auto portIndex = sifiveMetadataClass.getNumPorts();
353 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
354 {portIndex,
PortInfo(builder.getStringAttr(fieldName +
"_field_" +
357 sifiveMetadataClass.insertPorts(newPorts);
358 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
359 obj.getType(), topMod->getLoc());
360 builder.create<PropAssignOp>(blockarg, obj);
362 if (blackBoxMetadataClass)
364 builder.create<ObjectOp>(blackBoxMetadataClass,
365 builder.getStringAttr(
"blackbox_metadata")),
368 if (memoryMetadataClass)
370 builder.create<ObjectOp>(memoryMetadataClass,
371 builder.getStringAttr(
"memory_metadata")),
374 if (retimeModulesMetadataClass)
375 addPort(builder.create<ObjectOp>(
376 retimeModulesMetadataClass,
377 builder.getStringAttr(
"retime_modules_metadata")),
380 if (instanceInfo.
hasDut()) {
381 auto dutMod = instanceInfo.
getDut();
385 SmallVector<Value, 2> pathOpsToDut;
387 auto dutPaths = instancePathCache.getAbsolutePaths(dutMod);
389 for (
auto dutPath : dutPaths) {
390 SmallVector<Attribute> namepath;
392 for (
auto inst : dutPath)
394 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
395 return getModuleNamespace(mod);
397 if (namepath.empty())
401 auto leafInst = dutPath.leaf();
402 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
403 auto nla = nlaBuilder.create<hw::HierPathOp>(
405 nlaBuilder.getStringAttr(circtNamespace.newName(
"dutNLA")),
406 nlaBuilder.getArrayAttr(namepath));
408 pathOpsToDut.emplace_back(
createPathRef(leafInst, nla, builder));
411 auto pathList = builder.create<ListCreateOp>(
414 addPort(pathList,
"dutModulePath");
417 builder.setInsertionPointToEnd(topMod.getBodyBlock());
418 return builder.create<ObjectOp>(sifiveMetadataClass,
419 builder.getStringAttr(
"sifive_metadata"));
423 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
424 return moduleNamespaces.try_emplace(module, module).first->second;
426 MLIRContext *context;
432 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
433 ClassOp memorySchemaClass, extraPortsClass;
434 ClassOp memoryMetadataClass;
435 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
436 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
437 StringRef memoryParamNames[13] = {
438 "name",
"depth",
"width",
"maskBits",
439 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
440 "readLatency",
"hierarchy",
"inDut",
"extraPorts",
442 StringRef retimeModulesParamNames[1] = {
"moduleName"};
443 StringRef blackBoxModulesParamNames[1] = {
"moduleName"};
444 llvm::SmallDenseSet<StringRef> blackboxModules;
447 class CreateSiFiveMetadataPass
448 :
public circt::firrtl::impl::CreateSiFiveMetadataBase<
449 CreateSiFiveMetadataPass> {
450 LogicalResult emitRetimeModulesMetadata(ObjectModelIR &omir);
451 LogicalResult emitSitestBlackboxMetadata(ObjectModelIR &omir);
452 LogicalResult emitMemoryMetadata(ObjectModelIR &omir);
453 void runOnOperation()
override;
456 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
457 return moduleNamespaces.try_emplace(module, module).first->second;
460 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
466 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
467 this->replSeqMem = replSeqMem;
468 this->replSeqMemFile = replSeqMemFile.str();
476 CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
481 auto addSymbolToVerbatimOp =
483 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
485 if (
auto module = dyn_cast<FModuleLike>(op))
489 op, [&](
auto mod) -> hw::InnerSymbolNamespace & {
490 return getModuleNamespace(mod);
493 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
495 symbols.push_back(symbol);
498 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
504 auto createMemMetadata = [&](FMemModuleOp mem,
505 llvm::json::OStream &jsonStream,
506 std::string &seqMemConfStr,
507 SmallVectorImpl<Attribute> &jsonSymbols,
508 SmallVectorImpl<Attribute> &seqMemSymbols) {
511 auto width = mem.getDataWidth();
516 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 ||
width <= 0)
519 auto symId = seqMemSymbols.size();
520 seqMemSymbols.push_back(memExtSym);
522 auto isMasked = mem.isMasked();
523 auto maskGran =
width;
525 maskGran /= mem.getMaskBits();
528 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
529 if (!portStr.empty())
531 portStr += isMasked ?
"mwrite" :
"write";
533 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
534 if (!portStr.empty())
538 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
539 if (!portStr.empty())
541 portStr += isMasked ?
"mrw" :
"rw";
545 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
546 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
547 "}} depth " + Twine(mem.getDepth()) +
" width " +
548 Twine(
width) +
" ports " + portStr + maskGranStr +
"\n")
555 jsonStream.object([&] {
556 jsonStream.attribute(
"module_name",
557 addSymbolToVerbatimOp(mem, jsonSymbols));
558 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
559 jsonStream.attribute(
"width", (int64_t)
width);
560 jsonStream.attribute(
"masked", isMasked);
561 jsonStream.attribute(
"read", mem.getNumReadPorts());
562 jsonStream.attribute(
"write", mem.getNumWritePorts());
563 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
565 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
566 jsonStream.attributeArray(
"extra_ports", [&] {
567 for (
auto attr : mem.getExtraPorts()) {
568 jsonStream.object([&] {
569 auto port = cast<DictionaryAttr>(attr);
570 auto name = port.getAs<StringAttr>(
"name").getValue();
571 jsonStream.attribute(
"name", name);
572 auto direction = port.getAs<StringAttr>(
"direction").getValue();
573 jsonStream.attribute(
"direction", direction);
574 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
575 jsonStream.attribute(
"width", width);
580 SmallVector<std::string> hierNames;
581 jsonStream.attributeArray(
"hierarchy", [&] {
584 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
585 for (
auto p : paths) {
590 std::string hierName =
591 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
594 auto finalInst = p.leaf();
595 for (
auto inst : llvm::drop_end(p)) {
596 auto parentModule = inst->getParentOfType<FModuleOp>();
597 if (instanceInfo->
getDut() == parentModule)
599 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
601 hierName = hierName +
"." +
602 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
604 hierName += (
"." + finalInst.getInstanceName()).str();
606 hierNames.push_back(hierName);
609 if (llvm::any_of(p, [&](circt::igraph::InstanceOpInterface inst) {
610 return dutMod == inst->getParentOfType<FModuleOp>();
612 jsonStream.value(hierName);
618 std::string dutJsonBuffer;
619 llvm::raw_string_ostream dutOs(dutJsonBuffer);
620 llvm::json::OStream dutJson(dutOs, 2);
621 SmallVector<Attribute, 8> seqMemSymbols;
622 SmallVector<Attribute, 8> jsonSymbols;
624 std::string seqMemConfStr;
626 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
627 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
631 auto *context = &getContext();
632 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
633 circuitOp.getBodyBlock());
636 StringRef metadataDir =
"metadata";
638 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
639 metadataDir = dir.getValue();
643 SmallString<128> seqMemsJsonPath(metadataDir);
645 builder.create<emit::FileOp>(seqMemsJsonPath, [&] {
646 builder.create<sv::VerbatimOp>(dutJsonBuffer, ValueRange{},
647 builder.getArrayAttr(jsonSymbols));
652 if (replSeqMemFile.empty()) {
653 emitError(circuitOp->getLoc())
654 <<
"metadata emission failed, the option "
655 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
656 "valid seq mem metadata file";
660 builder.create<emit::FileOp>(replSeqMemFile, [&] {
661 builder.create<sv::VerbatimOp>(seqMemConfStr, ValueRange{},
662 builder.getArrayAttr(seqMemSymbols));
676 StringRef &filename) {
679 AnnotationSet::removeAnnotations(op, [&](
Annotation anno) {
681 if (error || !anno.
isClass(annoClass))
685 if (!filename.empty()) {
686 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
692 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
694 op->emitError(annoClass) <<
" requires a filename";
700 filename = filenameAttr.getValue();
701 if (filename.empty()) {
702 op->emitError(annoClass) <<
" requires a non-empty filename";
711 return failure(error);
717 CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
719 auto *context = &getContext();
727 if (filename.empty())
732 llvm::raw_string_ostream os(buffer);
733 llvm::json::OStream j(os, 2);
737 SmallVector<Attribute> symbols;
738 SmallString<3> placeholder;
740 for (
auto module : circuitOp.getBodyBlock()->getOps<FModuleLike>()) {
742 if (!AnnotationSet::removeAnnotations(module, retimeModuleAnnoClass))
747 j.value((
"{{" + Twine(index++) +
"}}").str());
748 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
749 omir.addRetimeModule(module);
754 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
755 circuitOp.getBodyBlock());
756 builder.create<emit::FileOp>(filename, [&] {
757 builder.create<sv::VerbatimOp>(builder.getStringAttr(buffer), ValueRange{},
758 builder.getArrayAttr(symbols));
766 CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
770 std::array<StringRef, 6> blackListedAnnos = {
774 auto *context = &getContext();
777 StringRef dutFilename, testFilename;
785 if (dutFilename.empty() && testFilename.empty())
791 SmallVector<StringRef> dutModules;
792 SmallVector<StringRef> testModules;
793 for (
auto extModule : circuitOp.getBodyBlock()->getOps<FExtModuleOp>()) {
796 if (!extModule.getDefname())
801 if (llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
802 return annos.hasAnnotation(blackListedAnno);
808 dutModules.push_back(*extModule.getDefname());
810 testModules.push_back(*extModule.getDefname());
812 omir.addBlackBoxModule(extModule);
816 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
817 StringRef filename) {
818 if (filename.empty())
822 std::sort(names.begin(), names.end());
823 names.erase(std::unique(names.begin(), names.end()), names.end());
828 llvm::raw_string_ostream os(buffer);
829 llvm::json::OStream j(os, 2);
831 for (
auto &name : names)
836 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
837 circuitOp.getBodyBlock());
839 builder.create<emit::FileOp>(filename, [&] {
844 createOutput(testModules, testFilename);
845 createOutput(dutModules, dutFilename);
850 void CreateSiFiveMetadataPass::runOnOperation() {
851 auto circuits = getOperation().getOps<CircuitOp>();
852 if (circuits.empty())
855 circuitOp = *circuits.begin();
857 if (!llvm::hasSingleElement(circuits)) {
858 mlir::emitError(circuitOp.getLoc(),
859 "cannot process multiple circuit operations")
860 .attachNote((*std::next(circuits.begin())).getLoc())
861 <<
"second circuit here";
862 return signalPassFailure();
865 auto &instanceGraph = getAnalysis<InstanceGraph>();
866 instanceInfo = &getAnalysis<InstanceInfo>();
867 ObjectModelIR omir(circuitOp, instanceGraph, *instanceInfo, moduleNamespaces);
869 if (failed(emitRetimeModulesMetadata(omir)) ||
870 failed(emitSitestBlackboxMetadata(omir)) ||
871 failed(emitMemoryMetadata(omir)))
872 return signalPassFailure();
874 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->getModule()))
875 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
876 auto portIndex = topMod.getNumPorts();
877 SmallVector<std::pair<unsigned, PortInfo>> ports = {
881 topMod.insertPorts(ports);
882 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
883 topMod->getLoc(), topMod.getBodyBlock());
884 auto objectCast = builderOM.create<ObjectAnyRefCastOp>(objectOp);
885 builderOM.create<PropAssignOp>(topMod.getArgument(portIndex), objectCast);
895 std::unique_ptr<mlir::Pass>
897 StringRef replSeqMemFile) {
898 return std::make_unique<CreateSiFiveMetadataPass>(replSeqMem, replSeqMemFile);
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
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.
bool anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op)
Return true if at least one instance is under (or transitively under) the effective design-under-test...
igraph::ModuleOpInterface getEffectiveDut()
Return the "effective" design-under-test.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
ClassType getInstanceTypeForClassLike(ClassLike classOp)
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.
std::unique_ptr< mlir::Pass > createCreateSiFiveMetadataPass(bool replSeqMem=false, mlir::StringRef replSeqMemFile="")
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 * 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.