24 #include "mlir/IR/ImplicitLocOpBuilder.h"
25 #include "mlir/IR/Location.h"
26 #include "mlir/Pass/Pass.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"
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 {
47 CircuitOp circtOp, FModuleOp dutMod,
InstanceGraph &instanceGraph,
48 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces)
49 : circtOp(circtOp), dutMod(dutMod),
52 moduleNamespaces(moduleNamespaces) {}
55 PathOp createPathRef(Operation *op, hw::HierPathOp nla,
56 mlir::ImplicitLocOpBuilder &builderOM) {
57 auto *context = op->getContext();
61 fields.append(
"id",
id);
67 annos.applyToOperation(op);
68 TargetKind kind = TargetKind::Reference;
69 if (isa<InstanceOp, FModuleLike>(op))
70 kind = TargetKind::Instance;
73 return builderOM.create<PathOp>(kind, id);
78 ClassOp buildSimpleClassOp(OpBuilder &odsBuilder, Location loc, Twine name,
79 ArrayRef<StringRef> fieldNames,
80 ArrayRef<Type> fieldTypes) {
81 SmallVector<PortInfo, 10> ports;
82 for (
auto [fieldName, fieldType] : llvm::zip(fieldNames, fieldTypes)) {
83 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
85 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
90 odsBuilder.create<ClassOp>(loc, odsBuilder.getStringAttr(name), ports);
91 Block *body = classOp.getBodyBlock();
92 auto prevLoc = odsBuilder.saveInsertionPoint();
93 odsBuilder.setInsertionPointToEnd(body);
94 auto args = body->getArguments();
95 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
96 odsBuilder.create<PropAssignOp>(loc, args[i + 1], args[i]);
98 odsBuilder.restoreInsertionPoint(prevLoc);
103 void createMemorySchema() {
104 auto *context = circtOp.getContext();
107 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
108 unknownLoc, circtOp.getBodyBlock());
113 mlir::Type extraPortsType[] = {
118 StringRef extraPortFields[3] = {
"name",
"direction",
"width"};
121 buildSimpleClassOp(builderOM, unknownLoc,
"ExtraPortsMemorySchema",
122 extraPortFields, extraPortsType);
124 mlir::Type classFieldTypes[12] = {
141 buildSimpleClassOp(builderOM, unknownLoc,
"MemorySchema",
142 memoryParamNames, classFieldTypes);
146 SmallVector<PortInfo> mports;
147 memoryMetadataClass = builderOM.create<ClassOp>(
148 builderOM.getStringAttr(
"MemoryMetadata"), mports);
151 void createRetimeModulesSchema() {
152 auto *context = circtOp.getContext();
154 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
155 unknownLoc, circtOp.getBodyBlock());
157 retimeModulesSchemaClass =
158 buildSimpleClassOp(builderOM, unknownLoc,
"RetimeModulesSchema",
159 retimeModulesParamNames, classFieldTypes);
161 SmallVector<PortInfo> mports;
162 retimeModulesMetadataClass = builderOM.create<ClassOp>(
163 builderOM.getStringAttr(
"RetimeModulesMetadata"), mports);
166 void addRetimeModule(FModuleLike module) {
167 if (!retimeModulesSchemaClass)
168 createRetimeModulesSchema();
169 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
170 module->getLoc(), retimeModulesMetadataClass.getBodyBlock());
174 builderOM.create<StringConstantOp>(module.getModuleNameAttr());
175 auto object = builderOM.create<ObjectOp>(retimeModulesSchemaClass,
176 module.getModuleNameAttr());
178 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
179 builderOM.create<PropAssignOp>(inPort, modEntry);
180 auto portIndex = retimeModulesMetadataClass.getNumPorts();
181 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
183 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
185 retimeModulesMetadataClass.insertPorts(newPorts);
186 auto blockarg = retimeModulesMetadataClass.getBodyBlock()->addArgument(
187 object.getType(), module->getLoc());
188 builderOM.create<PropAssignOp>(blockarg, object);
191 void addBlackBoxModulesSchema() {
192 auto *context = circtOp.getContext();
194 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
195 unknownLoc, circtOp.getBodyBlock());
197 blackBoxModulesSchemaClass =
198 buildSimpleClassOp(builderOM, unknownLoc,
"SitestBlackBoxModulesSchema",
199 blackBoxModulesParamNames, classFieldTypes);
200 SmallVector<PortInfo> mports;
201 blackBoxMetadataClass = builderOM.create<ClassOp>(
202 builderOM.getStringAttr(
"SitestBlackBoxMetadata"), mports);
205 void addBlackBoxModule(FExtModuleOp module) {
206 if (!blackBoxModulesSchemaClass)
207 addBlackBoxModulesSchema();
208 StringRef defName = *module.getDefname();
209 if (!blackboxModules.insert(defName).second)
211 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
212 module.getLoc(), blackBoxMetadataClass.getBodyBlock());
213 auto modEntry = builderOM.create<StringConstantOp>(module.getDefnameAttr());
214 auto object = builderOM.create<ObjectOp>(blackBoxModulesSchemaClass,
215 module.getModuleNameAttr());
217 auto inPort = builderOM.create<ObjectSubfieldOp>(object, 0);
218 builderOM.create<PropAssignOp>(inPort, modEntry);
219 auto portIndex = blackBoxMetadataClass.getNumPorts();
220 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
222 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
224 blackBoxMetadataClass.insertPorts(newPorts);
225 auto blockarg = blackBoxMetadataClass.getBodyBlock()->addArgument(
226 object.getType(), module->getLoc());
227 builderOM.create<PropAssignOp>(blockarg, object);
230 void addMemory(FMemModuleOp mem,
bool inDut) {
231 if (!memorySchemaClass)
232 createMemorySchema();
233 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
234 mem.getLoc(), memoryMetadataClass.getBodyBlock());
235 auto *context = builderOM.getContext();
236 auto createConstField = [&](Attribute constVal) -> Value {
237 if (
auto boolConstant = dyn_cast_or_null<mlir::BoolAttr>(constVal))
238 return builderOM.create<BoolConstantOp>(boolConstant);
239 if (
auto intConstant = dyn_cast_or_null<mlir::IntegerAttr>(constVal))
240 return builderOM.create<FIntegerConstantOp>(intConstant);
241 if (
auto strConstant = dyn_cast_or_null<mlir::StringAttr>(constVal))
242 return builderOM.create<StringConstantOp>(strConstant);
245 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
247 auto memPaths = instancePathCache.getAbsolutePaths(mem);
248 SmallVector<Value> memoryHierPaths;
249 for (
auto memPath : memPaths) {
250 Operation *finalInst = memPath.leaf();
251 SmallVector<Attribute> namepath;
252 bool foundDut = dutMod ==
nullptr;
253 for (
auto inst : memPath) {
255 if (inst->getParentOfType<FModuleOp>() == dutMod)
261 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
262 return getModuleNamespace(mod);
265 if (namepath.empty())
267 auto nla = nlaBuilder.create<hw::HierPathOp>(
269 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
270 nlaBuilder.getArrayAttr(namepath));
273 memoryHierPaths.emplace_back(createPathRef(finalInst, nla, builderOM));
275 auto hierpaths = builderOM.create<ListCreateOp>(
278 SmallVector<Value> memFields;
280 auto object = builderOM.create<ObjectOp>(memorySchemaClass, mem.getName());
281 SmallVector<Value> extraPortsList;
282 ClassType extraPortsType;
283 for (
auto attr : mem.getExtraPortsAttr()) {
285 auto port = cast<DictionaryAttr>(attr);
286 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
287 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
288 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
290 builderOM.create<ObjectOp>(extraPortsClass,
"extraPorts");
291 extraPortsType = extraPortsObj.getType();
292 auto inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 0);
293 builderOM.create<PropAssignOp>(inPort, portName);
294 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 2);
295 builderOM.create<PropAssignOp>(inPort, direction);
296 inPort = builderOM.create<ObjectSubfieldOp>(extraPortsObj, 4);
297 builderOM.create<PropAssignOp>(inPort,
width);
298 extraPortsList.push_back(extraPortsObj);
300 auto extraPorts = builderOM.create<ListCreateOp>(
301 memorySchemaClass.getPortType(22), extraPortsList);
302 for (
auto field : llvm::enumerate(memoryParamNames)) {
303 auto propVal = createConstField(
304 llvm::StringSwitch<TypedAttr>(field.value())
305 .Case(
"name", builderOM.getStringAttr(mem.getName()))
306 .Case(
"depth", mem.getDepthAttr())
307 .Case(
"width", mem.getDataWidthAttr())
308 .Case(
"maskBits", mem.getMaskBitsAttr())
309 .Case(
"readPorts", mem.getNumReadPortsAttr())
310 .Case(
"writePorts", mem.getNumWritePortsAttr())
311 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
312 .Case(
"readLatency", mem.getReadLatencyAttr())
313 .Case(
"writeLatency", mem.getWriteLatencyAttr())
314 .Case(
"hierarchy", {})
316 .Case(
"extraPorts", {}));
318 if (field.value() ==
"hierarchy")
321 propVal = extraPorts;
330 builderOM.create<ObjectSubfieldOp>(object, 2 * field.index());
331 builderOM.create<PropAssignOp>(inPort, propVal);
333 auto portIndex = memoryMetadataClass.getNumPorts();
334 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
335 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
337 memoryMetadataClass.insertPorts(newPorts);
338 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
339 object.getType(), mem->getLoc());
340 builderOM.create<PropAssignOp>(blockarg, object);
343 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
344 if (!blackBoxMetadataClass && !memoryMetadataClass &&
345 !retimeModulesMetadataClass)
347 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
349 SmallVector<PortInfo> mports;
350 auto sifiveMetadataClass = builder.create<ClassOp>(
351 builder.getStringAttr(
"SiFive_Metadata"), mports);
352 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
354 auto addPort = [&](Value obj, StringRef fieldName) {
355 auto portIndex = sifiveMetadataClass.getNumPorts();
356 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
357 {portIndex,
PortInfo(builder.getStringAttr(fieldName +
"_field_" +
360 sifiveMetadataClass.insertPorts(newPorts);
361 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
362 obj.getType(), topMod->getLoc());
363 builder.create<PropAssignOp>(blockarg, obj);
365 if (blackBoxMetadataClass)
367 builder.create<ObjectOp>(blackBoxMetadataClass,
368 builder.getStringAttr(
"blackbox_metadata")),
371 if (memoryMetadataClass)
373 builder.create<ObjectOp>(memoryMetadataClass,
374 builder.getStringAttr(
"memory_metadata")),
377 if (retimeModulesMetadataClass)
378 addPort(builder.create<ObjectOp>(
379 retimeModulesMetadataClass,
380 builder.getStringAttr(
"retime_modules_metadata")),
386 SmallVector<Value, 2> pathOpsToDut;
388 auto dutPaths = instancePathCache.getAbsolutePaths(dutMod);
390 for (
auto dutPath : dutPaths) {
391 SmallVector<Attribute> namepath;
393 for (
auto inst : dutPath)
395 inst, [&](
auto mod) -> hw::InnerSymbolNamespace & {
396 return getModuleNamespace(mod);
398 if (namepath.empty())
402 auto leafInst = dutPath.leaf();
403 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
404 auto nla = nlaBuilder.create<hw::HierPathOp>(
406 nlaBuilder.getStringAttr(circtNamespace.newName(
"dutNLA")),
407 nlaBuilder.getArrayAttr(namepath));
409 pathOpsToDut.emplace_back(createPathRef(leafInst, nla, builder));
411 auto *context = builder.getContext();
413 auto pathList = builder.create<ListCreateOp>(
416 addPort(pathList,
"dutModulePath");
419 builder.setInsertionPointToEnd(topMod.getBodyBlock());
420 return builder.create<ObjectOp>(sifiveMetadataClass,
421 builder.getStringAttr(
"sifive_metadata"));
425 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
426 return moduleNamespaces.try_emplace(module, module).first->second;
433 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
434 ClassOp memorySchemaClass, extraPortsClass;
435 ClassOp memoryMetadataClass;
436 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
437 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
438 StringRef memoryParamNames[12] = {
439 "name",
"depth",
"width",
"maskBits",
440 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
441 "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 DenseSet<Operation *> dutModuleSet;
462 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
468 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
469 this->replSeqMem = replSeqMem;
470 this->replSeqMemFile = replSeqMemFile.str();
478 CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
484 bool everythingInDUT =
486 omir.instancePathCache.instanceGraph.getTopLevelNode()->getModule() ==
489 auto addSymbolToVerbatimOp =
491 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
493 if (
auto module = dyn_cast<FModuleLike>(op))
497 op, [&](
auto mod) -> hw::InnerSymbolNamespace & {
498 return getModuleNamespace(mod);
501 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
503 symbols.push_back(symbol);
506 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
512 auto createMemMetadata = [&](FMemModuleOp mem,
513 llvm::json::OStream &jsonStream,
514 std::string &seqMemConfStr,
515 SmallVectorImpl<Attribute> &jsonSymbols,
516 SmallVectorImpl<Attribute> &seqMemSymbols) {
517 bool inDut = everythingInDUT || dutModuleSet.contains(mem);
518 omir.addMemory(mem, inDut);
520 auto width = mem.getDataWidth();
525 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 ||
width <= 0)
528 auto symId = seqMemSymbols.size();
529 seqMemSymbols.push_back(memExtSym);
531 auto isMasked = mem.isMasked();
532 auto maskGran =
width;
534 maskGran /= mem.getMaskBits();
537 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
538 if (!portStr.empty())
540 portStr += isMasked ?
"mwrite" :
"write";
542 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
543 if (!portStr.empty())
547 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
548 if (!portStr.empty())
550 portStr += isMasked ?
"mrw" :
"rw";
554 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
555 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
556 "}} depth " + Twine(mem.getDepth()) +
" width " +
557 Twine(
width) +
" ports " + portStr + maskGranStr +
"\n")
561 if (!everythingInDUT && !dutModuleSet.contains(mem))
564 jsonStream.object([&] {
565 jsonStream.attribute(
"module_name",
566 addSymbolToVerbatimOp(mem, jsonSymbols));
567 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
568 jsonStream.attribute(
"width", (int64_t)
width);
569 jsonStream.attribute(
"masked", isMasked);
570 jsonStream.attribute(
"read", mem.getNumReadPorts());
571 jsonStream.attribute(
"write", mem.getNumWritePorts());
572 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
574 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
575 jsonStream.attributeArray(
"extra_ports", [&] {
576 for (
auto attr : mem.getExtraPorts()) {
577 jsonStream.object([&] {
578 auto port = cast<DictionaryAttr>(attr);
579 auto name = port.getAs<StringAttr>(
"name").getValue();
580 jsonStream.attribute(
"name", name);
581 auto direction = port.getAs<StringAttr>(
"direction").getValue();
582 jsonStream.attribute(
"direction", direction);
583 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
584 jsonStream.attribute(
"width", width);
589 SmallVector<std::string> hierNames;
590 jsonStream.attributeArray(
"hierarchy", [&] {
593 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
594 for (
auto p : paths) {
599 std::string hierName =
600 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
603 auto finalInst = p.leaf();
604 for (
auto inst : llvm::drop_end(p)) {
605 auto parentModule = inst->getParentOfType<FModuleOp>();
606 if (dutMod == parentModule)
608 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
610 hierName = hierName +
"." +
611 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
613 hierName += (
"." + finalInst.getInstanceName()).str();
615 hierNames.push_back(hierName);
619 if (everythingInDUT ||
620 llvm::any_of(p, [&](circt::igraph::InstanceOpInterface inst) {
621 return llvm::all_of(inst.getReferencedModuleNamesAttr(),
622 [&](Attribute attr) {
623 return attr == dutMod.getNameAttr();
626 jsonStream.value(hierName);
632 std::string dutJsonBuffer;
633 llvm::raw_string_ostream dutOs(dutJsonBuffer);
634 llvm::json::OStream dutJson(dutOs, 2);
635 SmallVector<Attribute, 8> seqMemSymbols;
636 SmallVector<Attribute, 8> jsonSymbols;
638 std::string seqMemConfStr;
640 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
641 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
645 auto *context = &getContext();
646 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
647 circuitOp.getBodyBlock());
650 StringRef metadataDir =
"metadata";
652 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
653 metadataDir = dir.getValue();
657 SmallString<128> seqMemsJsonPath(metadataDir);
659 builder.create<emit::FileOp>(seqMemsJsonPath, [&] {
660 builder.create<sv::VerbatimOp>(dutJsonBuffer, ValueRange{},
661 builder.getArrayAttr(jsonSymbols));
666 if (replSeqMemFile.empty()) {
667 emitError(circuitOp->getLoc())
668 <<
"metadata emission failed, the option "
669 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
670 "valid seq mem metadata file";
674 builder.create<emit::FileOp>(replSeqMemFile, [&] {
675 builder.create<sv::VerbatimOp>(seqMemConfStr, ValueRange{},
676 builder.getArrayAttr(seqMemSymbols));
690 StringRef &filename) {
693 AnnotationSet::removeAnnotations(op, [&](
Annotation anno) {
695 if (error || !anno.
isClass(annoClass))
699 if (!filename.empty()) {
700 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
706 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
708 op->emitError(annoClass) <<
" requires a filename";
714 filename = filenameAttr.getValue();
715 if (filename.empty()) {
716 op->emitError(annoClass) <<
" requires a non-empty filename";
725 return failure(error);
731 CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
733 auto *context = &getContext();
741 if (filename.empty())
746 llvm::raw_string_ostream os(buffer);
747 llvm::json::OStream j(os, 2);
751 SmallVector<Attribute> symbols;
752 SmallString<3> placeholder;
754 for (
auto module : circuitOp.getBodyBlock()->getOps<FModuleLike>()) {
756 if (!AnnotationSet::removeAnnotations(module, retimeModuleAnnoClass))
761 j.value((
"{{" + Twine(index++) +
"}}").str());
762 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
763 omir.addRetimeModule(module);
768 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
769 circuitOp.getBodyBlock());
770 builder.create<emit::FileOp>(filename, [&] {
771 builder.create<sv::VerbatimOp>(builder.getStringAttr(buffer), ValueRange{},
772 builder.getArrayAttr(symbols));
780 CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
784 std::array<StringRef, 6> blackListedAnnos = {
788 auto *context = &getContext();
791 StringRef dutFilename, testFilename;
799 if (dutFilename.empty() && testFilename.empty())
805 SmallVector<StringRef> dutModules;
806 SmallVector<StringRef> testModules;
807 for (
auto extModule : circuitOp.getBodyBlock()->getOps<FExtModuleOp>()) {
810 if (!extModule.getDefname())
815 if (llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
816 return annos.hasAnnotation(blackListedAnno);
821 if (!dutMod || dutModuleSet.contains(extModule)) {
822 dutModules.push_back(*extModule.getDefname());
824 testModules.push_back(*extModule.getDefname());
826 omir.addBlackBoxModule(extModule);
830 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
831 StringRef filename) {
832 if (filename.empty())
836 std::sort(names.begin(), names.end());
837 names.erase(std::unique(names.begin(), names.end()), names.end());
842 llvm::raw_string_ostream os(buffer);
843 llvm::json::OStream j(os, 2);
845 for (
auto &name : names)
850 auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(context),
851 circuitOp.getBodyBlock());
853 builder.create<emit::FileOp>(filename, [&] {
858 createOutput(testModules, testFilename);
859 createOutput(dutModules, dutFilename);
864 void CreateSiFiveMetadataPass::runOnOperation() {
866 auto moduleOp = getOperation();
867 auto circuits = moduleOp.getOps<CircuitOp>();
868 if (circuits.empty())
870 auto cIter = circuits.begin();
871 circuitOp = *cIter++;
873 assert(cIter == circuits.end() &&
874 "cannot handle more than one CircuitOp in a mlir::ModuleOp");
876 auto *body = circuitOp.getBodyBlock();
878 auto it = llvm::find_if(*body, [&](Operation &op) ->
bool {
881 auto &instanceGraph = getAnalysis<InstanceGraph>();
882 if (it != body->end()) {
883 dutMod = dyn_cast<FModuleOp>(*it);
884 auto *node = instanceGraph.lookup(cast<igraph::ModuleOpInterface>(*it));
885 llvm::for_each(llvm::depth_first(node),
890 ObjectModelIR omir(circuitOp, dutMod, instanceGraph, moduleNamespaces);
892 if (failed(emitRetimeModulesMetadata(omir)) ||
893 failed(emitSitestBlackboxMetadata(omir)) ||
894 failed(emitMemoryMetadata(omir)))
895 return signalPassFailure();
896 auto *node = instanceGraph.getTopLevelNode();
897 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->
getModule()))
898 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
899 auto portIndex = topMod.getNumPorts();
900 SmallVector<std::pair<unsigned, PortInfo>> ports = {
904 topMod.insertPorts(ports);
905 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
906 topMod->getLoc(), topMod.getBodyBlock());
907 auto objectCast = builderOM.create<ObjectAnyRefCastOp>(objectOp);
908 builderOM.create<PropAssignOp>(topMod.getArgument(portIndex), objectCast);
916 dutModuleSet.empty();
919 std::unique_ptr<mlir::Pass>
921 StringRef replSeqMemFile) {
922 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...
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)
igraph::InstancePathCache InstancePathCache
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.