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"
40 using namespace circt;
41 using namespace firrtl;
45 struct ObjectModelIR {
49 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces)
50 : context(circtOp->getContext()), circtOp(circtOp),
53 instanceInfo(instanceInfo), moduleNamespaces(moduleNamespaces) {}
57 mlir::ImplicitLocOpBuilder &builderOM) {
60 TargetKind kind = TargetKind::Reference;
64 fields.append(
"id",
id);
70 annos.applyToOperation(op);
71 if (isa<InstanceOp, FModuleLike>(op))
72 kind = TargetKind::Instance;
76 return builderOM.create<PathOp>(kind, id);
79 void createMemorySchema() {
82 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
83 unknownLoc, circtOp.getBodyBlock());
88 mlir::Type extraPortsType[] = {
93 StringRef extraPortFields[3] = {
"name",
"direction",
"width"};
95 extraPortsClass = builderOM.create<ClassOp>(
96 "ExtraPortsMemorySchema", extraPortFields, extraPortsType);
98 mlir::Type classFieldTypes[13] = {
111 context, cast<PropertyType>(
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() {
128 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
129 unknownLoc, circtOp.getBodyBlock());
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"),
158 retimeModulesMetadataClass.insertPorts(newPorts);
159 auto blockarg = retimeModulesMetadataClass.getBodyBlock()->addArgument(
160 object.getType(), module->getLoc());
161 builderOM.create<PropAssignOp>(blockarg, object);
164 void addBlackBoxModulesSchema() {
166 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
167 unknownLoc, circtOp.getBodyBlock());
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) {
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 object = builderOM.create<ObjectOp>(blackBoxModulesSchemaClass,
187 module.getModuleNameAttr());
189 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
190 builderOM.create<PropAssignOp>(inPort, modEntry);
191 auto portIndex = blackBoxMetadataClass.getNumPorts();
192 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
194 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
196 blackBoxMetadataClass.insertPorts(newPorts);
197 auto blockarg = blackBoxMetadataClass.getBodyBlock()->addArgument(
198 object.getType(), module->getLoc());
199 builderOM.create<PropAssignOp>(blockarg, object);
202 void addMemory(FMemModuleOp mem) {
203 if (!memorySchemaClass)
204 createMemorySchema();
205 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
206 mem.getLoc(), memoryMetadataClass.getBodyBlock());
207 auto createConstField = [&](Attribute constVal) -> Value {
208 if (
auto boolConstant = dyn_cast_or_null<mlir::BoolAttr>(constVal))
209 return builderOM.create<BoolConstantOp>(boolConstant);
210 if (
auto intConstant = dyn_cast_or_null<mlir::IntegerAttr>(constVal))
211 return builderOM.create<FIntegerConstantOp>(intConstant);
212 if (
auto strConstant = dyn_cast_or_null<mlir::StringAttr>(constVal))
213 return builderOM.create<StringConstantOp>(strConstant);
216 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
218 auto memPaths = instancePathCache.getAbsolutePaths(mem);
219 SmallVector<Value> memoryHierPaths;
220 SmallVector<Value> finalInstanceNames;
233 for (
auto memPath : memPaths) {
235 igraph::InstanceOpInterface finalInst = memPath.leaf();
236 finalInstanceNames.emplace_back(builderOM.create<StringConstantOp>(
237 finalInst.getInstanceNameAttr()));
239 SmallVector<Attribute> namepath;
240 bool foundDut =
false;
244 igraph::InstanceOpInterface preExtractedLeafInstance;
245 for (
auto inst : llvm::drop_end(memPath)) {
248 inst->getParentOfType<FModuleOp>()))
254 if (inst->getParentOfType<LayerBlockOp>()) {
260 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
261 return getModuleNamespace(mod);
263 preExtractedLeafInstance = inst;
266 if (!namepath.empty()) {
268 auto nla = nlaBuilder.create<hw::HierPathOp>(
270 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
271 nlaBuilder.getArrayAttr(namepath));
272 nla.setVisibility(SymbolTable::Visibility::Private);
273 pathRef =
createPathRef(preExtractedLeafInstance, nla, builderOM);
282 memoryHierPaths.push_back(pathRef);
285 auto finalInstNamesList = builderOM.create<ListCreateOp>(
288 auto hierpaths = builderOM.create<ListCreateOp>(
291 SmallVector<Value> memFields;
293 auto object = builderOM.create<ObjectOp>(memorySchemaClass, mem.getName());
294 SmallVector<Value> extraPortsList;
295 ClassType extraPortsType;
296 for (
auto attr : mem.getExtraPortsAttr()) {
298 auto port = cast<DictionaryAttr>(attr);
299 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
300 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
301 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
303 builderOM.create<ObjectOp>(extraPortsClass,
"extraPorts");
304 extraPortsType = extraPortsObj.getType();
305 auto inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 0);
306 builderOM.create<PropAssignOp>(inPort, portName);
307 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 2);
308 builderOM.create<PropAssignOp>(inPort, direction);
309 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 4);
310 builderOM.create<PropAssignOp>(inPort, width);
311 extraPortsList.push_back(extraPortsObj);
313 auto extraPorts = builderOM.create<ListCreateOp>(
314 memorySchemaClass.getPortType(22), extraPortsList);
315 for (
auto field : llvm::enumerate(memoryParamNames)) {
316 auto propVal = createConstField(
317 llvm::StringSwitch<TypedAttr>(field.value())
318 .Case(
"name", builderOM.getStringAttr(mem.getName()))
319 .Case(
"depth", mem.getDepthAttr())
320 .Case(
"width", mem.getDataWidthAttr())
321 .Case(
"maskBits", mem.getMaskBitsAttr())
322 .Case(
"readPorts", mem.getNumReadPortsAttr())
323 .Case(
"writePorts", mem.getNumWritePortsAttr())
324 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
325 .Case(
"readLatency", mem.getReadLatencyAttr())
326 .Case(
"writeLatency", mem.getWriteLatencyAttr())
327 .Case(
"hierarchy", {})
329 .Case(
"extraPorts", {})
330 .Case(
"preExtInstName", {}));
332 if (field.value() ==
"hierarchy")
334 else if (field.value() ==
"preExtInstName")
335 propVal = finalInstNamesList;
337 propVal = extraPorts;
346 builderOM.create<ObjectSubfieldOp>(object, 2 * field.index());
347 builderOM.create<PropAssignOp>(inPort, propVal);
349 auto portIndex = memoryMetadataClass.getNumPorts();
350 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
351 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
353 memoryMetadataClass.insertPorts(newPorts);
354 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
355 object.getType(), mem->getLoc());
356 builderOM.create<PropAssignOp>(blockarg, object);
359 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
360 if (!blackBoxMetadataClass && !memoryMetadataClass &&
361 !retimeModulesMetadataClass && !instanceInfo.
hasDut())
363 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
365 SmallVector<PortInfo> mports;
366 auto sifiveMetadataClass = builder.create<ClassOp>(
367 builder.getStringAttr(
"SiFive_Metadata"), mports);
368 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
370 auto addPort = [&](Value obj, StringRef fieldName) {
371 auto portIndex = sifiveMetadataClass.getNumPorts();
372 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
373 {portIndex,
PortInfo(builder.getStringAttr(fieldName +
"_field_" +
376 sifiveMetadataClass.insertPorts(newPorts);
377 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
378 obj.getType(), topMod->getLoc());
379 builder.create<PropAssignOp>(blockarg, obj);
381 if (blackBoxMetadataClass)
383 builder.create<ObjectOp>(blackBoxMetadataClass,
384 builder.getStringAttr(
"blackbox_metadata")),
387 if (memoryMetadataClass)
389 builder.create<ObjectOp>(memoryMetadataClass,
390 builder.getStringAttr(
"memory_metadata")),
393 if (retimeModulesMetadataClass)
394 addPort(builder.create<ObjectOp>(
395 retimeModulesMetadataClass,
396 builder.getStringAttr(
"retime_modules_metadata")),
399 if (instanceInfo.
hasDut()) {
400 auto dutMod = instanceInfo.
getDut();
404 SmallVector<Value, 2> pathOpsToDut;
406 auto dutPaths = instancePathCache.getAbsolutePaths(dutMod);
408 for (
auto dutPath : dutPaths) {
409 SmallVector<Attribute> namepath;
411 for (
auto inst : dutPath)
413 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
414 return getModuleNamespace(mod);
416 if (namepath.empty())
420 auto leafInst = dutPath.leaf();
421 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
422 auto nla = nlaBuilder.create<hw::HierPathOp>(
424 nlaBuilder.getStringAttr(circtNamespace.newName(
"dutNLA")),
425 nlaBuilder.getArrayAttr(namepath));
426 nla.setVisibility(SymbolTable::Visibility::Private);
428 pathOpsToDut.emplace_back(
createPathRef(leafInst, nla, builder));
431 auto pathList = builder.create<ListCreateOp>(
434 addPort(pathList,
"dutModulePath");
437 builder.setInsertionPointToEnd(topMod.getBodyBlock());
438 return builder.create<ObjectOp>(sifiveMetadataClass,
439 builder.getStringAttr(
"sifive_metadata"));
443 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
444 return moduleNamespaces.try_emplace(module, module).first->second;
446 MLIRContext *context;
452 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
453 ClassOp memorySchemaClass, extraPortsClass;
454 ClassOp memoryMetadataClass;
455 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
456 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
457 StringRef memoryParamNames[13] = {
458 "name",
"depth",
"width",
"maskBits",
459 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
460 "readLatency",
"hierarchy",
"inDut",
"extraPorts",
462 StringRef retimeModulesParamNames[1] = {
"moduleName"};
463 StringRef blackBoxModulesParamNames[1] = {
"moduleName"};
464 llvm::SmallDenseSet<StringRef> blackboxModules;
467 class CreateSiFiveMetadataPass
468 :
public circt::firrtl::impl::CreateSiFiveMetadataBase<
469 CreateSiFiveMetadataPass> {
470 LogicalResult emitRetimeModulesMetadata(ObjectModelIR &omir);
471 LogicalResult emitSitestBlackboxMetadata(ObjectModelIR &omir);
472 LogicalResult emitMemoryMetadata(ObjectModelIR &omir);
473 void runOnOperation()
override;
476 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
477 return moduleNamespaces.try_emplace(module, module).first->second;
480 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
486 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
487 this->replSeqMem = replSeqMem;
488 this->replSeqMemFile = replSeqMemFile.str();
496 CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
501 auto addSymbolToVerbatimOp =
503 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
505 if (
auto module = dyn_cast<FModuleLike>(op))
509 op, [&](
auto mod) -> hw::InnerSymbolNamespace & {
510 return getModuleNamespace(mod);
513 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
515 symbols.push_back(symbol);
518 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
524 auto createMemMetadata = [&](FMemModuleOp mem,
525 llvm::json::OStream &jsonStream,
526 std::string &seqMemConfStr,
527 SmallVectorImpl<Attribute> &jsonSymbols,
528 SmallVectorImpl<Attribute> &seqMemSymbols) {
531 auto width = mem.getDataWidth();
536 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 || width <= 0)
539 auto symId = seqMemSymbols.size();
540 seqMemSymbols.push_back(memExtSym);
542 auto isMasked = mem.isMasked();
543 auto maskGran = width;
545 maskGran /= mem.getMaskBits();
548 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
549 if (!portStr.empty())
551 portStr += isMasked ?
"mwrite" :
"write";
553 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
554 if (!portStr.empty())
558 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
559 if (!portStr.empty())
561 portStr += isMasked ?
"mrw" :
"rw";
565 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
566 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
567 "}} depth " + Twine(mem.getDepth()) +
" width " +
568 Twine(width) +
" ports " + portStr + maskGranStr +
"\n")
575 jsonStream.object([&] {
576 jsonStream.attribute(
"module_name",
577 addSymbolToVerbatimOp(mem, jsonSymbols));
578 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
579 jsonStream.attribute(
"width", (int64_t)width);
580 jsonStream.attribute(
"masked", isMasked);
581 jsonStream.attribute(
"read", mem.getNumReadPorts());
582 jsonStream.attribute(
"write", mem.getNumWritePorts());
583 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
585 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
586 jsonStream.attributeArray(
"extra_ports", [&] {
587 for (
auto attr : mem.getExtraPorts()) {
588 jsonStream.object([&] {
589 auto port = cast<DictionaryAttr>(attr);
590 auto name = port.getAs<StringAttr>(
"name").getValue();
591 jsonStream.attribute(
"name", name);
592 auto direction = port.getAs<StringAttr>(
"direction").getValue();
593 jsonStream.attribute(
"direction", direction);
594 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
595 jsonStream.attribute(
"width", width);
600 jsonStream.attributeArray(
"hierarchy", [&] {
603 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
604 for (
auto p : paths) {
612 bool inDut =
false, underLayer =
false;
613 for (
auto inst : p) {
614 auto parent = inst->getParentOfType<FModuleOp>();
615 inDut |= parent == dutMod;
616 if (inst->getParentOfType<LayerBlockOp>())
619 if (!inDut || underLayer)
623 std::string hierName =
624 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
627 auto finalInst = p.leaf();
628 for (
auto inst : llvm::drop_end(p)) {
629 auto parentModule = inst->getParentOfType<FModuleOp>();
630 if (instanceInfo->
getDut() == parentModule)
632 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
634 hierName = hierName +
"." +
635 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
637 hierName += (
"." + finalInst.getInstanceName()).str();
639 jsonStream.value(hierName);
645 std::string dutJsonBuffer;
646 llvm::raw_string_ostream dutOs(dutJsonBuffer);
647 llvm::json::OStream dutJson(dutOs, 2);
648 SmallVector<Attribute, 8> seqMemSymbols;
649 SmallVector<Attribute, 8> jsonSymbols;
651 std::string seqMemConfStr;
653 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
654 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
658 auto *context = &getContext();
659 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
660 circuitOp.getBodyBlock());
663 StringRef metadataDir =
"metadata";
665 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
666 metadataDir = dir.getValue();
670 SmallString<128> seqMemsJsonPath(metadataDir);
672 builder.create<emit::FileOp>(seqMemsJsonPath, [&] {
673 builder.create<sv::VerbatimOp>(dutJsonBuffer, ValueRange{},
674 builder.getArrayAttr(jsonSymbols));
679 if (replSeqMemFile.empty()) {
680 emitError(circuitOp->getLoc())
681 <<
"metadata emission failed, the option "
682 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
683 "valid seq mem metadata file";
687 builder.create<emit::FileOp>(replSeqMemFile, [&] {
688 builder.create<sv::VerbatimOp>(seqMemConfStr, ValueRange{},
689 builder.getArrayAttr(seqMemSymbols));
703 StringRef &filename) {
706 AnnotationSet::removeAnnotations(op, [&](
Annotation anno) {
708 if (error || !anno.
isClass(annoClass))
712 if (!filename.empty()) {
713 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
719 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
721 op->emitError(annoClass) <<
" requires a filename";
727 filename = filenameAttr.getValue();
728 if (filename.empty()) {
729 op->emitError(annoClass) <<
" requires a non-empty filename";
738 return failure(error);
744 CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
746 auto *context = &getContext();
754 if (filename.empty())
759 llvm::raw_string_ostream os(buffer);
760 llvm::json::OStream j(os, 2);
764 SmallVector<Attribute> symbols;
765 SmallString<3> placeholder;
767 for (
auto module : circuitOp.getBodyBlock()->getOps<FModuleLike>()) {
769 if (!AnnotationSet::removeAnnotations(module, retimeModuleAnnoClass) ||
770 !instanceInfo->anyInstanceInEffectiveDesign(module))
775 j.value((
"{{" + Twine(index++) +
"}}").str());
776 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
777 omir.addRetimeModule(module);
782 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
783 circuitOp.getBodyBlock());
784 builder.create<emit::FileOp>(filename, [&] {
785 builder.create<sv::VerbatimOp>(builder.getStringAttr(buffer), ValueRange{},
786 builder.getArrayAttr(symbols));
794 CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
798 std::array<StringRef, 6> blackListedAnnos = {
802 auto *context = &getContext();
805 StringRef dutFilename, testFilename;
813 if (dutFilename.empty() && testFilename.empty())
819 SmallVector<StringRef> dutModules;
820 SmallVector<StringRef> testModules;
821 for (
auto extModule : circuitOp.getBodyBlock()->getOps<FExtModuleOp>()) {
824 if (!extModule.getDefname())
829 if (llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
830 return annos.hasAnnotation(blackListedAnno);
836 dutModules.push_back(*extModule.getDefname());
838 testModules.push_back(*extModule.getDefname());
840 omir.addBlackBoxModule(extModule);
844 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
845 StringRef filename) {
846 if (filename.empty())
850 std::sort(names.begin(), names.end());
851 names.erase(std::unique(names.begin(), names.end()), names.end());
856 llvm::raw_string_ostream os(buffer);
857 llvm::json::OStream j(os, 2);
859 for (
auto &name : names)
864 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
865 circuitOp.getBodyBlock());
867 builder.create<emit::FileOp>(filename, [&] {
872 createOutput(testModules, testFilename);
873 createOutput(dutModules, dutFilename);
878 void CreateSiFiveMetadataPass::runOnOperation() {
879 auto circuits = getOperation().getOps<CircuitOp>();
880 if (circuits.empty())
883 circuitOp = *circuits.begin();
885 if (!llvm::hasSingleElement(circuits)) {
886 mlir::emitError(circuitOp.getLoc(),
887 "cannot process multiple circuit operations")
888 .attachNote((*std::next(circuits.begin())).getLoc())
889 <<
"second circuit here";
890 return signalPassFailure();
893 auto &instanceGraph = getAnalysis<InstanceGraph>();
894 instanceInfo = &getAnalysis<InstanceInfo>();
895 ObjectModelIR omir(circuitOp, instanceGraph, *instanceInfo, moduleNamespaces);
897 if (failed(emitRetimeModulesMetadata(omir)) ||
898 failed(emitSitestBlackboxMetadata(omir)) ||
899 failed(emitMemoryMetadata(omir)))
900 return signalPassFailure();
902 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->getModule()))
903 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
904 auto portIndex = topMod.getNumPorts();
905 SmallVector<std::pair<unsigned, PortInfo>> ports = {
909 topMod.insertPorts(ports);
910 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
911 topMod->getLoc(), topMod.getBodyBlock());
912 auto objectCast = builderOM.create<ObjectAnyRefCastOp>(objectOp);
913 builderOM.create<PropAssignOp>(topMod.getArgument(portIndex), objectCast);
923 std::unique_ptr<mlir::Pass>
925 StringRef replSeqMemFile) {
926 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.