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;
234 for (
auto memPath : memPaths) {
236 igraph::InstanceOpInterface finalInst = memPath.leaf();
237 finalInstanceNames.emplace_back(builderOM.create<StringConstantOp>(
238 finalInst.getInstanceNameAttr()));
240 SmallVector<Attribute> namepath;
241 bool foundDut =
false;
245 igraph::InstanceOpInterface preExtractedLeafInstance;
246 for (
auto inst : llvm::drop_end(memPath)) {
249 inst->getParentOfType<FModuleOp>()))
255 if (inst->getParentOfType<LayerBlockOp>()) {
261 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
262 return getModuleNamespace(mod);
264 preExtractedLeafInstance = inst;
267 if (!namepath.empty()) {
269 auto nla = nlaBuilder.create<hw::HierPathOp>(
271 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
272 nlaBuilder.getArrayAttr(namepath));
273 nla.setVisibility(SymbolTable::Visibility::Private);
274 pathRef =
createPathRef(preExtractedLeafInstance, nla, builderOM);
283 memoryHierPaths.push_back(pathRef);
286 auto finalInstNamesList = builderOM.create<ListCreateOp>(
289 auto hierpaths = builderOM.create<ListCreateOp>(
292 SmallVector<Value> memFields;
294 auto object = builderOM.create<ObjectOp>(memorySchemaClass, mem.getName());
295 SmallVector<Value> extraPortsList;
296 ClassType extraPortsType;
297 for (
auto attr : mem.getExtraPortsAttr()) {
299 auto port = cast<DictionaryAttr>(attr);
300 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
301 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
302 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
304 builderOM.create<ObjectOp>(extraPortsClass,
"extraPorts");
305 extraPortsType = extraPortsObj.getType();
306 auto inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 0);
307 builderOM.create<PropAssignOp>(inPort, portName);
308 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 2);
309 builderOM.create<PropAssignOp>(inPort, direction);
310 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 4);
311 builderOM.create<PropAssignOp>(inPort,
width);
312 extraPortsList.push_back(extraPortsObj);
314 auto extraPorts = builderOM.create<ListCreateOp>(
315 memorySchemaClass.getPortType(22), extraPortsList);
316 for (
auto field : llvm::enumerate(memoryParamNames)) {
317 auto propVal = createConstField(
318 llvm::StringSwitch<TypedAttr>(field.value())
319 .Case(
"name", builderOM.getStringAttr(mem.getName()))
320 .Case(
"depth", mem.getDepthAttr())
321 .Case(
"width", mem.getDataWidthAttr())
322 .Case(
"maskBits", mem.getMaskBitsAttr())
323 .Case(
"readPorts", mem.getNumReadPortsAttr())
324 .Case(
"writePorts", mem.getNumWritePortsAttr())
325 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
326 .Case(
"readLatency", mem.getReadLatencyAttr())
327 .Case(
"writeLatency", mem.getWriteLatencyAttr())
328 .Case(
"hierarchy", {})
330 .Case(
"extraPorts", {})
331 .Case(
"preExtInstName", {}));
333 if (field.value() ==
"hierarchy")
335 else if (field.value() ==
"preExtInstName")
336 propVal = finalInstNamesList;
338 propVal = extraPorts;
347 builderOM.create<ObjectSubfieldOp>(object, 2 * field.index());
348 builderOM.create<PropAssignOp>(inPort, propVal);
350 auto portIndex = memoryMetadataClass.getNumPorts();
351 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
352 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
354 memoryMetadataClass.insertPorts(newPorts);
355 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
356 object.getType(), mem->getLoc());
357 builderOM.create<PropAssignOp>(blockarg, object);
360 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
361 if (!blackBoxMetadataClass && !memoryMetadataClass &&
362 !retimeModulesMetadataClass && !instanceInfo.
hasDut())
364 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
366 SmallVector<PortInfo> mports;
367 auto sifiveMetadataClass = builder.create<ClassOp>(
368 builder.getStringAttr(
"SiFive_Metadata"), mports);
369 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
371 auto addPort = [&](Value obj, StringRef fieldName) {
372 auto portIndex = sifiveMetadataClass.getNumPorts();
373 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
374 {portIndex,
PortInfo(builder.getStringAttr(fieldName +
"_field_" +
377 sifiveMetadataClass.insertPorts(newPorts);
378 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
379 obj.getType(), topMod->getLoc());
380 builder.create<PropAssignOp>(blockarg, obj);
382 if (blackBoxMetadataClass)
384 builder.create<ObjectOp>(blackBoxMetadataClass,
385 builder.getStringAttr(
"blackbox_metadata")),
388 if (memoryMetadataClass)
390 builder.create<ObjectOp>(memoryMetadataClass,
391 builder.getStringAttr(
"memory_metadata")),
394 if (retimeModulesMetadataClass)
395 addPort(builder.create<ObjectOp>(
396 retimeModulesMetadataClass,
397 builder.getStringAttr(
"retime_modules_metadata")),
400 if (instanceInfo.
hasDut()) {
401 auto dutMod = instanceInfo.
getDut();
405 SmallVector<Value, 2> pathOpsToDut;
407 auto dutPaths = instancePathCache.getAbsolutePaths(dutMod);
409 for (
auto dutPath : dutPaths) {
410 SmallVector<Attribute> namepath;
412 for (
auto inst : dutPath)
414 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
415 return getModuleNamespace(mod);
417 if (namepath.empty())
421 auto leafInst = dutPath.leaf();
422 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
423 auto nla = nlaBuilder.create<hw::HierPathOp>(
425 nlaBuilder.getStringAttr(circtNamespace.newName(
"dutNLA")),
426 nlaBuilder.getArrayAttr(namepath));
427 nla.setVisibility(SymbolTable::Visibility::Private);
429 pathOpsToDut.emplace_back(
createPathRef(leafInst, nla, builder));
432 auto pathList = builder.create<ListCreateOp>(
435 addPort(pathList,
"dutModulePath");
438 builder.setInsertionPointToEnd(topMod.getBodyBlock());
439 return builder.create<ObjectOp>(sifiveMetadataClass,
440 builder.getStringAttr(
"sifive_metadata"));
444 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
445 return moduleNamespaces.try_emplace(module, module).first->second;
447 MLIRContext *context;
453 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
454 ClassOp memorySchemaClass, extraPortsClass;
455 ClassOp memoryMetadataClass;
456 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
457 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
458 StringRef memoryParamNames[13] = {
459 "name",
"depth",
"width",
"maskBits",
460 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
461 "readLatency",
"hierarchy",
"inDut",
"extraPorts",
463 StringRef retimeModulesParamNames[1] = {
"moduleName"};
464 StringRef blackBoxModulesParamNames[1] = {
"moduleName"};
465 llvm::SmallDenseSet<StringRef> blackboxModules;
468 class CreateSiFiveMetadataPass
469 :
public circt::firrtl::impl::CreateSiFiveMetadataBase<
470 CreateSiFiveMetadataPass> {
471 LogicalResult emitRetimeModulesMetadata(ObjectModelIR &omir);
472 LogicalResult emitSitestBlackboxMetadata(ObjectModelIR &omir);
473 LogicalResult emitMemoryMetadata(ObjectModelIR &omir);
474 void runOnOperation()
override;
477 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
478 return moduleNamespaces.try_emplace(module, module).first->second;
481 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
487 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
488 this->replSeqMem = replSeqMem;
489 this->replSeqMemFile = replSeqMemFile.str();
497 CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
502 auto addSymbolToVerbatimOp =
504 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
506 if (
auto module = dyn_cast<FModuleLike>(op))
510 op, [&](
auto mod) -> hw::InnerSymbolNamespace & {
511 return getModuleNamespace(mod);
514 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
516 symbols.push_back(symbol);
519 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
525 auto createMemMetadata = [&](FMemModuleOp mem,
526 llvm::json::OStream &jsonStream,
527 std::string &seqMemConfStr,
528 SmallVectorImpl<Attribute> &jsonSymbols,
529 SmallVectorImpl<Attribute> &seqMemSymbols) {
532 auto width = mem.getDataWidth();
537 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 ||
width <= 0)
540 auto symId = seqMemSymbols.size();
541 seqMemSymbols.push_back(memExtSym);
543 auto isMasked = mem.isMasked();
544 auto maskGran =
width;
546 maskGran /= mem.getMaskBits();
549 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
550 if (!portStr.empty())
552 portStr += isMasked ?
"mwrite" :
"write";
554 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
555 if (!portStr.empty())
559 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
560 if (!portStr.empty())
562 portStr += isMasked ?
"mrw" :
"rw";
566 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
567 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
568 "}} depth " + Twine(mem.getDepth()) +
" width " +
569 Twine(
width) +
" ports " + portStr + maskGranStr +
"\n")
576 jsonStream.object([&] {
577 jsonStream.attribute(
"module_name",
578 addSymbolToVerbatimOp(mem, jsonSymbols));
579 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
580 jsonStream.attribute(
"width", (int64_t)
width);
581 jsonStream.attribute(
"masked", isMasked);
582 jsonStream.attribute(
"read", mem.getNumReadPorts());
583 jsonStream.attribute(
"write", mem.getNumWritePorts());
584 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
586 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
587 jsonStream.attributeArray(
"extra_ports", [&] {
588 for (
auto attr : mem.getExtraPorts()) {
589 jsonStream.object([&] {
590 auto port = cast<DictionaryAttr>(attr);
591 auto name = port.getAs<StringAttr>(
"name").getValue();
592 jsonStream.attribute(
"name", name);
593 auto direction = port.getAs<StringAttr>(
"direction").getValue();
594 jsonStream.attribute(
"direction", direction);
595 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
596 jsonStream.attribute(
"width", width);
601 jsonStream.attributeArray(
"hierarchy", [&] {
604 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
605 for (
auto p : paths) {
613 bool inDut =
false, underLayer =
false;
614 for (
auto inst : p) {
615 auto parent = inst->getParentOfType<FModuleOp>();
616 inDut |= parent == dutMod;
617 if (inst->getParentOfType<LayerBlockOp>())
620 if (!inDut || underLayer)
624 std::string hierName =
625 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
628 auto finalInst = p.leaf();
629 for (
auto inst : llvm::drop_end(p)) {
630 auto parentModule = inst->getParentOfType<FModuleOp>();
631 if (instanceInfo->
getDut() == parentModule)
633 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
635 hierName = hierName +
"." +
636 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
638 hierName += (
"." + finalInst.getInstanceName()).str();
640 jsonStream.value(hierName);
646 std::string dutJsonBuffer;
647 llvm::raw_string_ostream dutOs(dutJsonBuffer);
648 llvm::json::OStream dutJson(dutOs, 2);
649 SmallVector<Attribute, 8> seqMemSymbols;
650 SmallVector<Attribute, 8> jsonSymbols;
652 std::string seqMemConfStr;
654 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
655 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
659 auto *context = &getContext();
660 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
661 circuitOp.getBodyBlock());
664 StringRef metadataDir =
"metadata";
666 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
667 metadataDir = dir.getValue();
671 SmallString<128> seqMemsJsonPath(metadataDir);
673 builder.create<emit::FileOp>(seqMemsJsonPath, [&] {
674 builder.create<sv::VerbatimOp>(dutJsonBuffer, ValueRange{},
675 builder.getArrayAttr(jsonSymbols));
680 if (replSeqMemFile.empty()) {
681 emitError(circuitOp->getLoc())
682 <<
"metadata emission failed, the option "
683 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
684 "valid seq mem metadata file";
688 builder.create<emit::FileOp>(replSeqMemFile, [&] {
689 builder.create<sv::VerbatimOp>(seqMemConfStr, ValueRange{},
690 builder.getArrayAttr(seqMemSymbols));
704 StringRef &filename) {
707 AnnotationSet::removeAnnotations(op, [&](
Annotation anno) {
709 if (error || !anno.
isClass(annoClass))
713 if (!filename.empty()) {
714 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
720 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
722 op->emitError(annoClass) <<
" requires a filename";
728 filename = filenameAttr.getValue();
729 if (filename.empty()) {
730 op->emitError(annoClass) <<
" requires a non-empty filename";
739 return failure(error);
745 CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
747 auto *context = &getContext();
755 if (filename.empty())
760 llvm::raw_string_ostream os(buffer);
761 llvm::json::OStream j(os, 2);
765 SmallVector<Attribute> symbols;
766 SmallString<3> placeholder;
768 for (
auto module : circuitOp.getBodyBlock()->getOps<FModuleLike>()) {
770 if (!AnnotationSet::removeAnnotations(module, retimeModuleAnnoClass) ||
771 !instanceInfo->anyInstanceInEffectiveDesign(module))
776 j.value((
"{{" + Twine(index++) +
"}}").str());
777 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
778 omir.addRetimeModule(module);
783 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
784 circuitOp.getBodyBlock());
785 builder.create<emit::FileOp>(filename, [&] {
786 builder.create<sv::VerbatimOp>(builder.getStringAttr(buffer), ValueRange{},
787 builder.getArrayAttr(symbols));
795 CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
799 std::array<StringRef, 6> blackListedAnnos = {
803 auto *context = &getContext();
806 StringRef dutFilename, testFilename;
814 if (dutFilename.empty() && testFilename.empty())
820 SmallVector<StringRef> dutModules;
821 SmallVector<StringRef> testModules;
822 for (
auto extModule : circuitOp.getBodyBlock()->getOps<FExtModuleOp>()) {
825 if (!extModule.getDefname())
830 if (llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
831 return annos.hasAnnotation(blackListedAnno);
837 dutModules.push_back(*extModule.getDefname());
839 testModules.push_back(*extModule.getDefname());
841 omir.addBlackBoxModule(extModule);
845 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
846 StringRef filename) {
847 if (filename.empty())
851 std::sort(names.begin(), names.end());
852 names.erase(std::unique(names.begin(), names.end()), names.end());
857 llvm::raw_string_ostream os(buffer);
858 llvm::json::OStream j(os, 2);
860 for (
auto &name : names)
865 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
866 circuitOp.getBodyBlock());
868 builder.create<emit::FileOp>(filename, [&] {
873 createOutput(testModules, testFilename);
874 createOutput(dutModules, dutFilename);
879 void CreateSiFiveMetadataPass::runOnOperation() {
880 auto circuits = getOperation().getOps<CircuitOp>();
881 if (circuits.empty())
884 circuitOp = *circuits.begin();
886 if (!llvm::hasSingleElement(circuits)) {
887 mlir::emitError(circuitOp.getLoc(),
888 "cannot process multiple circuit operations")
889 .attachNote((*std::next(circuits.begin())).getLoc())
890 <<
"second circuit here";
891 return signalPassFailure();
894 auto &instanceGraph = getAnalysis<InstanceGraph>();
895 instanceInfo = &getAnalysis<InstanceInfo>();
896 ObjectModelIR omir(circuitOp, instanceGraph, *instanceInfo, moduleNamespaces);
898 if (failed(emitRetimeModulesMetadata(omir)) ||
899 failed(emitSitestBlackboxMetadata(omir)) ||
900 failed(emitMemoryMetadata(omir)))
901 return signalPassFailure();
903 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->getModule()))
904 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
905 auto portIndex = topMod.getNumPorts();
906 SmallVector<std::pair<unsigned, PortInfo>> ports = {
910 topMod.insertPorts(ports);
911 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
912 topMod->getLoc(), topMod.getBodyBlock());
913 auto objectCast = builderOM.create<ObjectAnyRefCastOp>(objectOp);
914 builderOM.create<PropAssignOp>(topMod.getArgument(portIndex), objectCast);
924 std::unique_ptr<mlir::Pass>
926 StringRef replSeqMemFile) {
927 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.
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.
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.