25 #include "mlir/IR/ImplicitLocOpBuilder.h"
26 #include "mlir/IR/Location.h"
27 #include "llvm/ADT/DepthFirstIterator.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"
33 using namespace circt;
34 using namespace firrtl;
38 struct ObjectModelIR {
40 CircuitOp circtOp, FModuleOp dutMod,
InstanceGraph &instanceGraph,
41 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces)
42 : circtOp(circtOp), dutMod(dutMod),
45 moduleNamespaces(moduleNamespaces) {}
48 PathOp createPathRef(Operation *op, hw::HierPathOp nla,
49 mlir::ImplicitLocOpBuilder &builderOM) {
50 auto *context = op->getContext();
54 fields.append(
"id",
id);
60 annos.applyToOperation(op);
61 TargetKind kind = TargetKind::Reference;
62 if (isa<InstanceOp, FModuleLike>(op))
63 kind = TargetKind::Instance;
66 return builderOM.create<PathOp>(kind, id);
71 ClassOp buildSimpleClassOp(OpBuilder &odsBuilder, Location loc, Twine name,
72 ArrayRef<StringRef> fieldNames,
73 ArrayRef<Type> fieldTypes) {
74 SmallVector<PortInfo, 10> ports;
75 for (
auto [fieldName, fieldType] : llvm::zip(fieldNames, fieldTypes)) {
76 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
78 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
83 odsBuilder.create<ClassOp>(loc, odsBuilder.getStringAttr(name), ports);
84 Block *body = classOp.getBodyBlock();
85 auto prevLoc = odsBuilder.saveInsertionPoint();
86 odsBuilder.setInsertionPointToEnd(body);
87 auto args = body->getArguments();
88 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
89 odsBuilder.create<PropAssignOp>(loc, args[i + 1], args[i]);
91 odsBuilder.restoreInsertionPoint(prevLoc);
96 void createMemorySchema() {
97 auto *context = circtOp.getContext();
100 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
101 unknownLoc, circtOp.getBodyBlock());
106 mlir::Type extraPortsType[] = {
111 StringRef extraPortFields[3] = {
"name",
"direction",
"width"};
114 buildSimpleClassOp(builderOM, unknownLoc,
"ExtraPortsMemorySchema",
115 extraPortFields, extraPortsType);
117 mlir::Type classFieldTypes[12] = {
134 buildSimpleClassOp(builderOM, unknownLoc,
"MemorySchema",
135 memoryParamNames, classFieldTypes);
139 SmallVector<PortInfo> mports;
140 memoryMetadataClass = builderOM.create<ClassOp>(
141 builderOM.getStringAttr(
"MemoryMetadata"), mports);
144 void createRetimeModulesSchema() {
145 auto *context = circtOp.getContext();
147 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
148 unknownLoc, circtOp.getBodyBlock());
150 retimeModulesSchemaClass =
151 buildSimpleClassOp(builderOM, unknownLoc,
"RetimeModulesSchema",
152 retimeModulesParamNames, classFieldTypes);
154 SmallVector<PortInfo> mports;
155 retimeModulesMetadataClass = builderOM.create<ClassOp>(
156 builderOM.getStringAttr(
"RetimeModulesMetadata"), mports);
159 void addRetimeModule(FModuleLike module) {
160 if (!retimeModulesSchemaClass)
161 createRetimeModulesSchema();
162 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
163 module->getLoc(), retimeModulesMetadataClass.getBodyBlock());
167 builderOM.create<StringConstantOp>(module.getModuleNameAttr());
168 auto object = builderOM.create<ObjectOp>(retimeModulesSchemaClass,
169 module.getModuleNameAttr());
171 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
172 builderOM.create<PropAssignOp>(inPort, modEntry);
173 auto portIndex = retimeModulesMetadataClass.getNumPorts();
174 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
176 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
178 retimeModulesMetadataClass.insertPorts(newPorts);
179 auto blockarg = retimeModulesMetadataClass.getBodyBlock()->addArgument(
180 object.getType(), module->getLoc());
181 builderOM.create<PropAssignOp>(blockarg, object);
184 void addBlackBoxModulesSchema() {
185 auto *context = circtOp.getContext();
187 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
188 unknownLoc, circtOp.getBodyBlock());
190 blackBoxModulesSchemaClass =
191 buildSimpleClassOp(builderOM, unknownLoc,
"SitestBlackBoxModulesSchema",
192 blackBoxModulesParamNames, classFieldTypes);
193 SmallVector<PortInfo> mports;
194 blackBoxMetadataClass = builderOM.create<ClassOp>(
195 builderOM.getStringAttr(
"SitestBlackBoxMetadata"), mports);
198 void addBlackBoxModule(FExtModuleOp module) {
199 if (!blackBoxModulesSchemaClass)
200 addBlackBoxModulesSchema();
201 StringRef defName = *module.getDefname();
202 if (!blackboxModules.insert(defName).second)
204 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
205 module.getLoc(), blackBoxMetadataClass.getBodyBlock());
206 auto modEntry = builderOM.create<StringConstantOp>(module.getDefnameAttr());
207 auto object = builderOM.create<ObjectOp>(blackBoxModulesSchemaClass,
208 module.getModuleNameAttr());
210 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
211 builderOM.create<PropAssignOp>(inPort, modEntry);
212 auto portIndex = blackBoxMetadataClass.getNumPorts();
213 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
215 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
217 blackBoxMetadataClass.insertPorts(newPorts);
218 auto blockarg = blackBoxMetadataClass.getBodyBlock()->addArgument(
219 object.getType(), module->getLoc());
220 builderOM.create<PropAssignOp>(blockarg, object);
223 void addMemory(FMemModuleOp mem,
bool inDut) {
224 if (!memorySchemaClass)
225 createMemorySchema();
226 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
227 mem.getLoc(), memoryMetadataClass.getBodyBlock());
228 auto *context = builderOM.getContext();
229 auto createConstField = [&](Attribute constVal) -> Value {
230 if (
auto boolConstant = dyn_cast_or_null<mlir::BoolAttr>(constVal))
231 return builderOM.create<BoolConstantOp>(boolConstant);
232 if (
auto intConstant = dyn_cast_or_null<mlir::IntegerAttr>(constVal))
233 return builderOM.create<FIntegerConstantOp>(intConstant);
234 if (
auto strConstant = dyn_cast_or_null<mlir::StringAttr>(constVal))
235 return builderOM.create<StringConstantOp>(strConstant);
238 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
240 auto memPaths = instancePathCache.getAbsolutePaths(mem);
241 SmallVector<Value> memoryHierPaths;
242 for (
auto memPath : memPaths) {
243 Operation *finalInst = memPath.leaf();
244 SmallVector<Attribute> namepath;
245 bool foundDut = dutMod ==
nullptr;
246 for (
auto inst : memPath) {
248 if (inst->getParentOfType<FModuleOp>() == dutMod)
254 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
255 return getModuleNamespace(mod);
258 if (namepath.empty())
260 auto nla = nlaBuilder.create<hw::HierPathOp>(
262 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
263 nlaBuilder.getArrayAttr(namepath));
266 memoryHierPaths.emplace_back(createPathRef(finalInst, nla, builderOM));
268 auto hierpaths = builderOM.create<ListCreateOp>(
271 SmallVector<Value> memFields;
273 auto object = builderOM.create<ObjectOp>(memorySchemaClass, mem.getName());
274 SmallVector<Value> extraPortsList;
275 ClassType extraPortsType;
276 for (
auto attr : mem.getExtraPortsAttr()) {
278 auto port = cast<DictionaryAttr>(attr);
279 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
280 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
281 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
283 builderOM.create<ObjectOp>(extraPortsClass,
"extraPorts");
284 extraPortsType = extraPortsObj.getType();
285 auto inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 0);
286 builderOM.create<PropAssignOp>(inPort, portName);
287 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 2);
288 builderOM.create<PropAssignOp>(inPort, direction);
289 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 4);
290 builderOM.create<PropAssignOp>(inPort,
width);
291 extraPortsList.push_back(extraPortsObj);
293 auto extraPorts = builderOM.create<ListCreateOp>(
294 memorySchemaClass.getPortType(22), extraPortsList);
295 for (
auto field : llvm::enumerate(memoryParamNames)) {
296 auto propVal = createConstField(
297 llvm::StringSwitch<TypedAttr>(field.value())
298 .Case(
"name", builderOM.getStringAttr(mem.getName()))
299 .Case(
"depth", mem.getDepthAttr())
300 .Case(
"width", mem.getDataWidthAttr())
301 .Case(
"maskBits", mem.getMaskBitsAttr())
302 .Case(
"readPorts", mem.getNumReadPortsAttr())
303 .Case(
"writePorts", mem.getNumWritePortsAttr())
304 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
305 .Case(
"readLatency", mem.getReadLatencyAttr())
306 .Case(
"writeLatency", mem.getWriteLatencyAttr())
307 .Case(
"hierarchy", {})
309 .Case(
"extraPorts", {}));
311 if (field.value().equals(
"hierarchy"))
314 propVal = extraPorts;
323 builderOM.create<ObjectSubfieldOp>(object, 2 * field.index());
324 builderOM.create<PropAssignOp>(inPort, propVal);
326 auto portIndex = memoryMetadataClass.getNumPorts();
327 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
328 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
330 memoryMetadataClass.insertPorts(newPorts);
331 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
332 object.getType(), mem->getLoc());
333 builderOM.create<PropAssignOp>(blockarg, object);
336 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
337 if (!blackBoxMetadataClass && !memoryMetadataClass &&
338 !retimeModulesMetadataClass)
340 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
342 SmallVector<PortInfo> mports;
343 auto sifiveMetadataClass =
builder.create<ClassOp>(
344 builder.getStringAttr(
"SiFive_Metadata"), mports);
345 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
347 auto addPort = [&](Value obj, StringRef fieldName) {
348 auto portIndex = sifiveMetadataClass.getNumPorts();
349 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
353 sifiveMetadataClass.insertPorts(newPorts);
354 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
355 obj.getType(), topMod->getLoc());
356 builder.create<PropAssignOp>(blockarg, obj);
358 if (blackBoxMetadataClass)
360 builder.create<ObjectOp>(blackBoxMetadataClass,
361 builder.getStringAttr(
"blackbox_metadata")),
364 if (memoryMetadataClass)
366 builder.create<ObjectOp>(memoryMetadataClass,
367 builder.getStringAttr(
"memory_metadata")),
370 if (retimeModulesMetadataClass)
371 addPort(
builder.create<ObjectOp>(
372 retimeModulesMetadataClass,
373 builder.getStringAttr(
"retime_modules_metadata")),
376 builder.setInsertionPointToEnd(topMod.getBodyBlock());
377 return builder.create<ObjectOp>(sifiveMetadataClass,
378 builder.getStringAttr(
"sifive_metadata"));
382 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
383 return moduleNamespaces.try_emplace(module, module).first->second;
390 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
391 ClassOp memorySchemaClass, extraPortsClass;
392 ClassOp memoryMetadataClass;
393 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
394 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
395 StringRef memoryParamNames[12] = {
396 "name",
"depth",
"width",
"maskBits",
397 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
398 "readLatency",
"hierarchy",
"inDut",
"extraPorts"};
399 StringRef retimeModulesParamNames[1] = {
"moduleName"};
400 StringRef blackBoxModulesParamNames[1] = {
"moduleName"};
401 llvm::SmallDenseSet<StringRef> blackboxModules;
404 class CreateSiFiveMetadataPass
405 :
public CreateSiFiveMetadataBase<CreateSiFiveMetadataPass> {
406 LogicalResult emitRetimeModulesMetadata(ObjectModelIR &omir);
407 LogicalResult emitSitestBlackboxMetadata(ObjectModelIR &omir);
408 LogicalResult emitMemoryMetadata(ObjectModelIR &omir);
409 void runOnOperation()
override;
412 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
413 return moduleNamespaces.try_emplace(module, module).first->second;
416 DenseSet<Operation *> dutModuleSet;
418 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
424 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
425 this->replSeqMem = replSeqMem;
426 this->replSeqMemFile = replSeqMemFile.str();
434 CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
440 bool everythingInDUT =
442 omir.instancePathCache.instanceGraph.getTopLevelNode()->getModule() ==
445 auto addSymbolToVerbatimOp =
447 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
449 if (
auto module = dyn_cast<FModuleLike>(op))
453 op, [&](
auto mod) -> hw::InnerSymbolNamespace & {
454 return getModuleNamespace(mod);
457 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
459 symbols.push_back(symbol);
462 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
468 auto createMemMetadata = [&](FMemModuleOp mem,
469 llvm::json::OStream &jsonStream,
470 std::string &seqMemConfStr,
471 SmallVectorImpl<Attribute> &jsonSymbols,
472 SmallVectorImpl<Attribute> &seqMemSymbols) {
473 bool inDut = everythingInDUT || dutModuleSet.contains(mem);
474 omir.addMemory(mem, inDut);
476 auto width = mem.getDataWidth();
481 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 ||
width <= 0)
484 auto symId = seqMemSymbols.size();
485 seqMemSymbols.push_back(memExtSym);
487 auto isMasked = mem.isMasked();
488 auto maskGran =
width;
490 maskGran /= mem.getMaskBits();
493 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
494 if (!portStr.empty())
496 portStr += isMasked ?
"mwrite" :
"write";
498 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
499 if (!portStr.empty())
503 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
504 if (!portStr.empty())
506 portStr += isMasked ?
"mrw" :
"rw";
510 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
511 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
512 "}} depth " + Twine(mem.getDepth()) +
" width " +
513 Twine(
width) +
" ports " + portStr + maskGranStr +
"\n")
517 if (!everythingInDUT && !dutModuleSet.contains(mem))
520 jsonStream.object([&] {
521 jsonStream.attribute(
"module_name",
522 addSymbolToVerbatimOp(mem, jsonSymbols));
523 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
524 jsonStream.attribute(
"width", (int64_t)
width);
525 jsonStream.attribute(
"masked", isMasked);
526 jsonStream.attribute(
"read", mem.getNumReadPorts());
527 jsonStream.attribute(
"write", mem.getNumWritePorts());
528 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
530 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
531 jsonStream.attributeArray(
"extra_ports", [&] {
532 for (
auto attr : mem.getExtraPorts()) {
533 jsonStream.object([&] {
534 auto port = cast<DictionaryAttr>(attr);
535 auto name = port.getAs<StringAttr>(
"name").getValue();
536 jsonStream.attribute(
"name", name);
537 auto direction = port.getAs<StringAttr>(
"direction").getValue();
538 jsonStream.attribute(
"direction", direction);
539 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
540 jsonStream.attribute(
"width", width);
545 SmallVector<std::string> hierNames;
546 jsonStream.attributeArray(
"hierarchy", [&] {
549 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
550 for (
auto p : paths) {
555 std::string hierName =
556 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
559 auto finalInst = p.leaf();
560 for (
auto inst : llvm::drop_end(p)) {
561 auto parentModule = inst->getParentOfType<FModuleOp>();
562 if (dutMod == parentModule)
564 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
566 hierName = hierName +
"." +
567 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
569 hierName += (
"." + finalInst.getInstanceName()).str();
571 hierNames.push_back(hierName);
575 if (everythingInDUT ||
576 llvm::any_of(p, [&](circt::igraph::InstanceOpInterface inst) {
577 return llvm::all_of(inst.getReferencedModuleNamesAttr(),
578 [&](Attribute attr) {
579 return attr == dutMod.getNameAttr();
582 jsonStream.value(hierName);
588 std::string dutJsonBuffer;
589 llvm::raw_string_ostream dutOs(dutJsonBuffer);
590 llvm::json::OStream dutJson(dutOs, 2);
591 SmallVector<Attribute, 8> seqMemSymbols;
592 SmallVector<Attribute, 8> jsonSymbols;
594 std::string seqMemConfStr;
596 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
597 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
601 auto *context = &getContext();
603 circuitOp.getBodyBlock());
606 StringRef metadataDir =
"metadata";
608 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
609 metadataDir = dir.getValue();
613 SmallString<128> seqMemsJsonPath(metadataDir);
615 builder.create<emit::FileOp>(seqMemsJsonPath, [&] {
616 builder.create<sv::VerbatimOp>(dutJsonBuffer, ValueRange{},
617 builder.getArrayAttr(jsonSymbols));
622 if (replSeqMemFile.empty()) {
623 emitError(circuitOp->getLoc())
624 <<
"metadata emission failed, the option "
625 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
626 "valid seq mem metadata file";
630 builder.create<emit::FileOp>(replSeqMemFile, [&] {
631 builder.create<sv::VerbatimOp>(seqMemConfStr, ValueRange{},
632 builder.getArrayAttr(seqMemSymbols));
646 StringRef &filename) {
649 AnnotationSet::removeAnnotations(op, [&](
Annotation anno) {
651 if (error || !anno.
isClass(annoClass))
655 if (!filename.empty()) {
656 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
662 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
664 op->emitError(annoClass) <<
" requires a filename";
670 filename = filenameAttr.getValue();
671 if (filename.empty()) {
672 op->emitError(annoClass) <<
" requires a non-empty filename";
681 return failure(error);
687 CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
689 auto *context = &getContext();
697 if (filename.empty())
702 llvm::raw_string_ostream os(buffer);
703 llvm::json::OStream j(os, 2);
707 SmallVector<Attribute> symbols;
708 SmallString<3> placeholder;
710 for (
auto module : circuitOp.getBodyBlock()->getOps<FModuleLike>()) {
712 if (!AnnotationSet::removeAnnotations(module, retimeModuleAnnoClass))
717 j.value((
"{{" + Twine(index++) +
"}}").str());
718 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
719 omir.addRetimeModule(module);
725 circuitOp.getBodyBlock());
726 builder.create<emit::FileOp>(filename, [&] {
727 builder.create<sv::VerbatimOp>(
builder.getStringAttr(buffer), ValueRange{},
728 builder.getArrayAttr(symbols));
736 CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
740 std::array<StringRef, 6> blackListedAnnos = {
744 auto *context = &getContext();
747 StringRef dutFilename, testFilename;
755 if (dutFilename.empty() && testFilename.empty())
761 SmallVector<StringRef> dutModules;
762 SmallVector<StringRef> testModules;
763 for (
auto extModule : circuitOp.getBodyBlock()->getOps<FExtModuleOp>()) {
766 if (!extModule.getDefname())
771 if (llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
772 return annos.hasAnnotation(blackListedAnno);
777 if (!dutMod || dutModuleSet.contains(extModule)) {
778 dutModules.push_back(*extModule.getDefname());
780 testModules.push_back(*extModule.getDefname());
782 omir.addBlackBoxModule(extModule);
786 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
787 StringRef filename) {
788 if (filename.empty())
792 std::sort(names.begin(), names.end());
793 names.erase(std::unique(names.begin(), names.end()), names.end());
798 llvm::raw_string_ostream os(buffer);
799 llvm::json::OStream j(os, 2);
801 for (
auto &name : names)
807 circuitOp.getBodyBlock());
809 builder.create<emit::FileOp>(filename, [&] {
814 createOutput(testModules, testFilename);
815 createOutput(dutModules, dutFilename);
820 void CreateSiFiveMetadataPass::runOnOperation() {
822 auto moduleOp = getOperation();
823 auto circuits = moduleOp.getOps<CircuitOp>();
824 if (circuits.empty())
826 auto cIter = circuits.begin();
827 circuitOp = *cIter++;
829 assert(cIter == circuits.end() &&
830 "cannot handle more than one CircuitOp in a mlir::ModuleOp");
832 auto *body = circuitOp.getBodyBlock();
834 auto it = llvm::find_if(*body, [&](Operation &op) ->
bool {
837 auto &instanceGraph = getAnalysis<InstanceGraph>();
838 if (it != body->end()) {
839 dutMod = dyn_cast<FModuleOp>(*it);
840 auto *node = instanceGraph.lookup(cast<igraph::ModuleOpInterface>(*it));
841 llvm::for_each(llvm::depth_first(node),
846 ObjectModelIR omir(circuitOp, dutMod, instanceGraph, moduleNamespaces);
848 if (failed(emitRetimeModulesMetadata(omir)) ||
849 failed(emitSitestBlackboxMetadata(omir)) ||
850 failed(emitMemoryMetadata(omir)))
851 return signalPassFailure();
852 auto *node = instanceGraph.getTopLevelNode();
853 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->
getModule()))
854 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
855 auto portIndex = topMod.getNumPorts();
856 SmallVector<std::pair<unsigned, PortInfo>> ports = {
859 objectOp.getType(), Direction::Out)}};
860 topMod.insertPorts(ports);
861 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
862 topMod->getLoc(), topMod.getBodyBlock());
863 builderOM.create<PropAssignOp>(topMod.getArgument(portIndex), objectOp);
871 dutModuleSet.empty();
874 std::unique_ptr<mlir::Pass>
876 StringRef replSeqMemFile) {
877 return std::make_unique<CreateSiFiveMetadataPass>(replSeqMem, replSeqMemFile);
assert(baseType &&"element must be base type")
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...
bool hasAnnotation(StringRef className) const
Return true if we have an annotation with the specified class name.
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.
This is a Node in the InstanceGraph.
auto getModule()
Get the module that this node is tracking.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
ClassType getInstanceTypeForClassLike(ClassLike classOp)
constexpr const char * blackBoxAnnoClass
constexpr const char * sitestBlackBoxAnnoClass
constexpr const char * metadataDirectoryAttrName
constexpr const char * sitestTestHarnessBlackBoxAnnoClass
constexpr const char * dutAnnoClass
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.