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"
41using namespace firrtl;
49 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces)
50 : context(circtOp->getContext()), circtOp(circtOp),
53 instanceInfo(instanceInfo), moduleNamespaces(moduleNamespaces) {}
57 mlir::ImplicitLocOpBuilder &builderOM) {
59 auto id = DistinctAttr::create(UnitAttr::get(context));
60 TargetKind kind = TargetKind::Reference;
64 fields.append(
"id",
id);
65 fields.append(
"class", StringAttr::get(context,
"circt.tracker"));
67 fields.append(
"circt.nonlocal", mlir::FlatSymbolRefAttr::get(nla));
69 annos.addAnnotations(DictionaryAttr::get(context, fields));
70 annos.applyToOperation(op);
71 if (isa<InstanceOp, FModuleLike>(op))
72 kind = TargetKind::Instance;
76 return PathOp::create(builderOM, kind,
id);
79 void createMemorySchema() {
81 auto unknownLoc = mlir::UnknownLoc::get(context);
82 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
83 unknownLoc, circtOp.getBodyBlock());
88 mlir::Type extraPortsType[] = {
89 StringType::get(context),
90 StringType::get(context),
91 FIntegerType::get(context)
93 StringRef extraPortFields[3] = {
"name",
"direction",
"width"};
95 extraPortsClass = ClassOp::create(builderOM,
"ExtraPortsMemorySchema",
96 extraPortFields, extraPortsType);
98 mlir::Type classFieldTypes[14] = {
99 StringType::get(context),
100 FIntegerType::get(context),
101 FIntegerType::get(context),
102 FIntegerType::get(context),
103 FIntegerType::get(context),
104 FIntegerType::get(context),
105 FIntegerType::get(context),
106 FIntegerType::get(context),
107 FIntegerType::get(context),
108 StringType::get(context),
109 ListType::get(context, cast<PropertyType>(PathType::get(context))),
110 BoolType::get(context),
112 context, cast<PropertyType>(
113 detail::getInstanceTypeForClassLike(extraPortsClass))),
114 ListType::get(context, cast<PropertyType>(StringType::get(context))),
117 memorySchemaClass = ClassOp::create(builderOM,
"MemorySchema",
118 memoryParamNames, classFieldTypes);
122 SmallVector<PortInfo> mports;
123 memoryMetadataClass = ClassOp::create(
124 builderOM, builderOM.getStringAttr(
"MemoryMetadata"), mports);
127 void createRetimeModulesSchema() {
128 auto unknownLoc = mlir::UnknownLoc::get(context);
129 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
130 unknownLoc, circtOp.getBodyBlock());
131 Type classFieldTypes[] = {StringType::get(context)};
132 retimeModulesSchemaClass =
133 ClassOp::create(builderOM,
"RetimeModulesSchema",
134 retimeModulesParamNames, classFieldTypes);
136 SmallVector<PortInfo> mports;
137 retimeModulesMetadataClass = ClassOp::create(
138 builderOM, builderOM.getStringAttr(
"RetimeModulesMetadata"), mports);
141 void addRetimeModule(FModuleLike module) {
142 if (!retimeModulesSchemaClass)
143 createRetimeModulesSchema();
144 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
145 module->getLoc(), retimeModulesMetadataClass.getBodyBlock());
149 StringConstantOp::create(builderOM, module.getModuleNameAttr());
150 auto object = ObjectOp::create(builderOM, retimeModulesSchemaClass,
151 module.getModuleNameAttr());
153 auto inPort = ObjectSubfieldOp::create(builderOM,
object, 0);
154 PropAssignOp::create(builderOM, inPort, modEntry);
155 auto portIndex = retimeModulesMetadataClass.getNumPorts();
156 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
158 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
159 object.getType(), Direction::Out)}};
160 retimeModulesMetadataClass.insertPorts(newPorts);
161 auto blockarg = retimeModulesMetadataClass.getBodyBlock()->addArgument(
162 object.getType(), module->getLoc());
163 PropAssignOp::create(builderOM, blockarg,
object);
166 void addBlackBoxModulesSchema() {
167 auto unknownLoc = mlir::UnknownLoc::get(context);
168 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
169 unknownLoc, circtOp.getBodyBlock());
170 Type classFieldTypes[] = {
171 StringType::get(context), BoolType::get(context),
172 ListType::get(context, cast<PropertyType>(StringType::get(context)))};
173 blackBoxModulesSchemaClass =
174 ClassOp::create(builderOM,
"SitestBlackBoxModulesSchema",
175 blackBoxModulesParamNames, classFieldTypes);
176 SmallVector<PortInfo> mports;
177 blackBoxMetadataClass = ClassOp::create(
178 builderOM, builderOM.getStringAttr(
"SitestBlackBoxMetadata"), mports);
181 void addBlackBoxModule(FExtModuleOp module,
bool inDut,
182 ArrayRef<StringRef> libraries) {
183 if (!blackBoxModulesSchemaClass)
184 addBlackBoxModulesSchema();
185 StringRef defName = *
module.getDefname();
186 if (!blackboxModules.insert(defName).second)
188 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
189 module.getLoc(), blackBoxMetadataClass.getBodyBlock());
191 StringConstantOp::create(builderOM, module.getDefnameAttr());
192 auto inDutAttr = BoolConstantOp::create(builderOM, inDut);
194 SmallVector<Value> libValues;
195 for (StringRef libName : libraries) {
197 if (libName == defName) {
198 libNameAttr = modEntry;
200 libNameAttr = StringConstantOp::create(
201 builderOM, builderOM.getStringAttr(libName));
203 libValues.push_back(libNameAttr);
205 auto blackBoxResourcesList = ListCreateOp::create(
208 builderOM.getContext(),
209 cast<PropertyType>(StringType::get(builderOM.getContext()))),
212 auto object = ObjectOp::create(builderOM, blackBoxModulesSchemaClass,
213 module.getModuleNameAttr());
215 auto inPortModuleName = ObjectSubfieldOp::create(builderOM,
object, 0);
216 PropAssignOp::create(builderOM, inPortModuleName, modEntry);
217 auto inPortInDut = ObjectSubfieldOp::create(builderOM,
object, 2);
218 PropAssignOp::create(builderOM, inPortInDut, inDutAttr);
219 auto inPortBlackBoxResources =
220 ObjectSubfieldOp::create(builderOM,
object, 4);
221 PropAssignOp::create(builderOM, inPortBlackBoxResources,
222 blackBoxResourcesList);
223 auto portIndex = blackBoxMetadataClass.getNumPorts();
224 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
226 PortInfo(builderOM.getStringAttr(module.getName() +
"_field"),
227 object.getType(), Direction::Out)}};
228 blackBoxMetadataClass.insertPorts(newPorts);
229 auto blockarg = blackBoxMetadataClass.getBodyBlock()->addArgument(
230 object.getType(), module->getLoc());
231 PropAssignOp::create(builderOM, blockarg,
object);
234 void addMemory(FMemModuleOp mem) {
235 if (!memorySchemaClass)
236 createMemorySchema();
237 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
238 mem.getLoc(), memoryMetadataClass.getBodyBlock());
239 auto createConstField = [&](Attribute constVal) -> Value {
240 if (
auto boolConstant = dyn_cast_or_null<mlir::BoolAttr>(constVal))
241 return BoolConstantOp::create(builderOM, boolConstant);
242 if (
auto intConstant = dyn_cast_or_null<mlir::IntegerAttr>(constVal))
243 return FIntegerConstantOp::create(builderOM, intConstant);
244 if (
auto strConstant = dyn_cast_or_null<mlir::StringAttr>(constVal))
245 return StringConstantOp::create(builderOM, strConstant);
248 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
250 auto memPaths = instancePathCache.getAbsolutePaths(mem);
251 SmallVector<Value> memoryHierPaths;
252 SmallVector<Value> finalInstanceNames;
265 for (
auto memPath : memPaths) {
267 igraph::InstanceOpInterface finalInst = memPath.leaf();
268 finalInstanceNames.emplace_back(StringConstantOp::create(
269 builderOM, finalInst.getInstanceNameAttr()));
271 SmallVector<Attribute> namepath;
272 bool foundDut =
false;
276 igraph::InstanceOpInterface preExtractedLeafInstance;
277 for (
auto inst :
llvm::drop_end(memPath)) {
280 inst->getParentOfType<FModuleOp>()))
286 if (inst->getParentOfType<LayerBlockOp>()) {
293 return getModuleNamespace(mod);
295 preExtractedLeafInstance = inst;
298 if (!namepath.empty()) {
300 auto nla = hw::HierPathOp::create(
301 nlaBuilder, mem->getLoc(),
302 nlaBuilder.getStringAttr(circtNamespace.newName(
"memNLA")),
303 nlaBuilder.getArrayAttr(namepath));
304 nla.setVisibility(SymbolTable::Visibility::Private);
305 pathRef =
createPathRef(preExtractedLeafInstance, nla, builderOM);
314 memoryHierPaths.push_back(pathRef);
317 auto finalInstNamesList = ListCreateOp::create(
319 ListType::get(context, cast<PropertyType>(StringType::get(context))),
321 auto hierpaths = ListCreateOp::create(
323 ListType::get(context, cast<PropertyType>(PathType::get(context))),
325 SmallVector<Value> memFields;
327 auto object = ObjectOp::create(builderOM, memorySchemaClass, mem.getName());
328 SmallVector<Value> extraPortsList;
329 ClassType extraPortsType;
330 for (
auto attr : mem.getExtraPortsAttr()) {
332 auto port = cast<DictionaryAttr>(attr);
333 auto portName = createConstField(port.getAs<StringAttr>(
"name"));
334 auto direction = createConstField(port.getAs<StringAttr>(
"direction"));
335 auto width = createConstField(port.getAs<IntegerAttr>(
"width"));
337 ObjectOp::create(builderOM, extraPortsClass,
"extraPorts");
338 extraPortsType = extraPortsObj.getType();
339 auto inPort = ObjectSubfieldOp::create(builderOM, extraPortsObj, 0);
340 PropAssignOp::create(builderOM, inPort, portName);
341 inPort = ObjectSubfieldOp::create(builderOM, extraPortsObj, 2);
342 PropAssignOp::create(builderOM, inPort, direction);
343 inPort = ObjectSubfieldOp::create(builderOM, extraPortsObj, 4);
344 PropAssignOp::create(builderOM, inPort, width);
345 extraPortsList.push_back(extraPortsObj);
347 auto extraPorts = ListCreateOp::create(
348 builderOM, memorySchemaClass.getPortType(24), extraPortsList);
349 for (
auto field :
llvm::enumerate(memoryParamNames)) {
350 auto propVal = createConstField(
351 llvm::StringSwitch<TypedAttr>(field.value())
352 .Case(
"name", builderOM.getStringAttr(mem.getName()))
353 .Case(
"depth", mem.getDepthAttr())
354 .Case(
"width", mem.getDataWidthAttr())
355 .Case(
"maskBits", mem.getMaskBitsAttr())
356 .Case(
"readPorts", mem.getNumReadPortsAttr())
357 .Case(
"writePorts", mem.getNumWritePortsAttr())
358 .Case(
"readwritePorts", mem.getNumReadWritePortsAttr())
359 .Case(
"readLatency", mem.getReadLatencyAttr())
360 .Case(
"writeLatency", mem.getWriteLatencyAttr())
361 .Case(
"hierarchy", {})
362 .Case(
"inDut", BoolAttr::get(context, inDut))
363 .Case(
"extraPorts", {})
364 .Case(
"preExtInstName", {})
365 .Case(
"ruwBehavior", builderOM.getStringAttr(
366 stringifyRUWBehavior(mem.getRuw()))));
368 if (field.value() ==
"hierarchy")
370 else if (field.value() ==
"preExtInstName")
371 propVal = finalInstNamesList;
373 propVal = extraPorts;
382 ObjectSubfieldOp::create(builderOM,
object, 2 * field.index());
383 PropAssignOp::create(builderOM, inPort, propVal);
385 auto portIndex = memoryMetadataClass.getNumPorts();
386 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
387 {portIndex,
PortInfo(builderOM.getStringAttr(mem.getName() +
"_field"),
388 object.getType(), Direction::Out)}};
389 memoryMetadataClass.insertPorts(newPorts);
390 auto blockarg = memoryMetadataClass.getBodyBlock()->addArgument(
391 object.getType(), mem->getLoc());
392 PropAssignOp::create(builderOM, blockarg,
object);
395 ObjectOp instantiateSifiveMetadata(FModuleOp topMod) {
396 if (!blackBoxMetadataClass && !memoryMetadataClass &&
397 !retimeModulesMetadataClass && !instanceInfo.
hasDut())
399 auto builder = mlir::ImplicitLocOpBuilder::atBlockEnd(
400 mlir::UnknownLoc::get(circtOp->getContext()), circtOp.getBodyBlock());
401 SmallVector<PortInfo> mports;
402 auto sifiveMetadataClass = ClassOp::create(
403 builder, builder.getStringAttr(
"SiFive_Metadata"), mports);
404 builder.setInsertionPointToStart(sifiveMetadataClass.getBodyBlock());
406 auto addPort = [&](Value obj, StringRef fieldName) {
407 auto portIndex = sifiveMetadataClass.getNumPorts();
408 SmallVector<std::pair<unsigned, PortInfo>> newPorts = {
409 {portIndex,
PortInfo(builder.getStringAttr(fieldName +
"_field_" +
411 obj.getType(), Direction::Out)}};
412 sifiveMetadataClass.insertPorts(newPorts);
413 auto blockarg = sifiveMetadataClass.getBodyBlock()->addArgument(
414 obj.getType(), topMod->getLoc());
415 PropAssignOp::create(builder, blockarg, obj);
417 if (blackBoxMetadataClass)
418 addPort(ObjectOp::create(builder, blackBoxMetadataClass,
419 builder.getStringAttr(
"blackbox_metadata")),
422 if (memoryMetadataClass)
423 addPort(ObjectOp::create(builder, memoryMetadataClass,
424 builder.getStringAttr(
"memory_metadata")),
427 if (retimeModulesMetadataClass)
429 ObjectOp::create(builder, retimeModulesMetadataClass,
430 builder.getStringAttr(
"retime_modules_metadata")),
433 if (instanceInfo.
hasDut()) {
434 auto dutMod = instanceInfo.
getDut();
438 SmallVector<Value, 2> pathOpsToDut;
440 auto dutPaths = instancePathCache.getAbsolutePaths(dutMod);
442 for (
auto dutPath : dutPaths) {
443 SmallVector<Attribute> namepath;
445 for (
auto inst : dutPath)
448 return getModuleNamespace(mod);
450 if (namepath.empty())
454 auto leafInst = dutPath.leaf();
455 auto nlaBuilder = OpBuilder::atBlockBegin(circtOp.getBodyBlock());
456 auto nla = hw::HierPathOp::create(
457 nlaBuilder, dutMod->getLoc(),
458 nlaBuilder.getStringAttr(circtNamespace.newName(
"dutNLA")),
459 nlaBuilder.getArrayAttr(namepath));
460 nla.setVisibility(SymbolTable::Visibility::Private);
462 pathOpsToDut.emplace_back(
createPathRef(leafInst, nla, builder));
465 auto pathList = ListCreateOp::create(
467 ListType::get(context, cast<PropertyType>(PathType::get(context))),
469 addPort(pathList,
"dutModulePath");
472 builder.setInsertionPointToEnd(topMod.getBodyBlock());
473 return ObjectOp::create(builder, sifiveMetadataClass,
474 builder.getStringAttr(
"sifive_metadata"));
479 return moduleNamespaces.try_emplace(module, module).first->second;
481 MLIRContext *context;
487 DenseMap<Operation *, hw::InnerSymbolNamespace> &moduleNamespaces;
488 ClassOp memorySchemaClass, extraPortsClass;
489 ClassOp memoryMetadataClass;
490 ClassOp retimeModulesMetadataClass, retimeModulesSchemaClass;
491 ClassOp blackBoxModulesSchemaClass, blackBoxMetadataClass;
492 StringRef memoryParamNames[14] = {
493 "name",
"depth",
"width",
"maskBits",
494 "readPorts",
"writePorts",
"readwritePorts",
"writeLatency",
495 "readLatency",
"ruwBehavior",
"hierarchy",
"inDut",
496 "extraPorts",
"preExtInstName"};
497 StringRef retimeModulesParamNames[1] = {
"moduleName"};
498 StringRef blackBoxModulesParamNames[3] = {
"moduleName",
"inDut",
"libraries"};
499 llvm::SmallDenseSet<StringRef> blackboxModules;
502class CreateSiFiveMetadataPass
503 :
public circt::firrtl::impl::CreateSiFiveMetadataBase<
504 CreateSiFiveMetadataPass> {
507 LogicalResult emitRetimeModulesMetadata(ObjectModelIR &omir);
508 LogicalResult emitSitestBlackboxMetadata(ObjectModelIR &omir);
509 LogicalResult emitMemoryMetadata(ObjectModelIR &omir);
510 void runOnOperation()
override;
514 return moduleNamespaces.try_emplace(module, module).first->second;
517 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
523 CreateSiFiveMetadataPass(
bool replSeqMem, StringRef replSeqMemFile) {
524 this->replSeqMem = replSeqMem;
525 this->replSeqMemFile = replSeqMemFile.str();
533CreateSiFiveMetadataPass::emitMemoryMetadata(ObjectModelIR &omir) {
538 auto addSymbolToVerbatimOp =
540 llvm::SmallVectorImpl<Attribute> &symbols) -> SmallString<8> {
542 if (
auto module = dyn_cast<FModuleLike>(op))
543 symbol = FlatSymbolRefAttr::get(module);
547 return getModuleNamespace(mod);
550 auto [it, inserted] = symbolIndices.try_emplace(symbol, symbols.size());
552 symbols.push_back(symbol);
555 (
"{{" + Twine(it->second) +
"}}").
toVector(str);
561 auto createMemMetadata = [&](FMemModuleOp mem,
562 llvm::json::OStream &jsonStream,
563 std::string &seqMemConfStr,
564 SmallVectorImpl<Attribute> &jsonSymbols,
565 SmallVectorImpl<Attribute> &seqMemSymbols) {
568 auto width = mem.getDataWidth();
571 if (mem.getReadLatency() != 1 || mem.getWriteLatency() != 1 || width <= 0)
573 auto memExtSym = FlatSymbolRefAttr::get(SymbolTable::getSymbolName(mem));
574 auto symId = seqMemSymbols.size();
575 seqMemSymbols.push_back(memExtSym);
577 auto isMasked = mem.isMasked();
578 auto maskGran = width;
580 maskGran /= mem.getMaskBits();
583 for (uint32_t i = 0; i < mem.getNumWritePorts(); ++i) {
584 if (!portStr.empty())
586 portStr += isMasked ?
"mwrite" :
"write";
588 for (uint32_t i = 0; i < mem.getNumReadPorts(); ++i) {
589 if (!portStr.empty())
593 for (uint32_t i = 0; i < mem.getNumReadWritePorts(); ++i) {
594 if (!portStr.empty())
596 portStr += isMasked ?
"mrw" :
"rw";
600 !isMasked ?
"" :
" mask_gran " + std::to_string(maskGran);
602 seqMemConfStr = (StringRef(seqMemConfStr) +
"name {{" + Twine(symId) +
603 "}} depth " + Twine(mem.getDepth()) +
" width " +
604 Twine(width) +
" ports " + portStr + maskGranStr +
605 (mem.getRuw() == RUWBehavior::Undefined
607 :
" ruw " + stringifyRUWBehavior(mem.getRuw())) +
615 jsonStream.object([&] {
616 jsonStream.attribute(
"module_name",
617 addSymbolToVerbatimOp(mem, jsonSymbols));
618 jsonStream.attribute(
"depth", (int64_t)mem.getDepth());
619 jsonStream.attribute(
"width", (int64_t)width);
620 jsonStream.attribute(
"masked", isMasked);
621 jsonStream.attribute(
"read", mem.getNumReadPorts());
622 jsonStream.attribute(
"write", mem.getNumWritePorts());
623 jsonStream.attribute(
"readwrite", mem.getNumReadWritePorts());
624 jsonStream.attribute(
"ruw_behavior", stringifyRUWBehavior(mem.getRuw()));
626 jsonStream.attribute(
"mask_granularity", (int64_t)maskGran);
627 jsonStream.attributeArray(
"extra_ports", [&] {
628 for (
auto attr : mem.getExtraPorts()) {
629 jsonStream.object([&] {
630 auto port = cast<DictionaryAttr>(attr);
631 auto name = port.getAs<StringAttr>(
"name").getValue();
632 jsonStream.attribute(
"name", name);
633 auto direction = port.getAs<StringAttr>(
"direction").getValue();
634 jsonStream.attribute(
"direction", direction);
635 auto width = port.getAs<IntegerAttr>(
"width").getUInt();
636 jsonStream.attribute(
"width", width);
641 jsonStream.attributeArray(
"hierarchy", [&] {
644 auto paths = omir.instancePathCache.getAbsolutePaths(mem);
645 for (
auto p : paths) {
653 bool inDut =
false, underLayer =
false;
654 for (
auto inst : p) {
655 auto parent = inst->getParentOfType<FModuleOp>();
656 inDut |= parent == dutMod;
657 if (inst->getParentOfType<LayerBlockOp>())
660 if (!inDut || underLayer)
664 std::string hierName =
665 addSymbolToVerbatimOp(top->getParentOfType<FModuleOp>(),
668 auto finalInst = p.leaf();
669 for (
auto inst :
llvm::drop_end(p)) {
670 auto parentModule = inst->getParentOfType<FModuleOp>();
671 if (instanceInfo->
getDut() == parentModule)
673 addSymbolToVerbatimOp(parentModule, jsonSymbols).c_str();
675 hierName = hierName +
"." +
676 addSymbolToVerbatimOp(inst, jsonSymbols).c_str();
678 hierName += (
"." + finalInst.getInstanceName()).str();
680 jsonStream.value(hierName);
686 std::string dutJsonBuffer;
687 llvm::raw_string_ostream dutOs(dutJsonBuffer);
688 llvm::json::OStream dutJson(dutOs, 2);
689 SmallVector<Attribute, 8> seqMemSymbols;
690 SmallVector<Attribute, 8> jsonSymbols;
692 std::string seqMemConfStr;
694 for (
auto mem : circuitOp.getOps<FMemModuleOp>())
695 createMemMetadata(mem, dutJson, seqMemConfStr, jsonSymbols,
699 auto *context = &getContext();
700 auto builder = ImplicitLocOpBuilder::atBlockEnd(UnknownLoc::get(context),
701 circuitOp.getBodyBlock());
704 StringRef metadataDir =
"metadata";
706 if (
auto dir = dirAnno.getMember<StringAttr>(
"dirname"))
707 metadataDir = dir.getValue();
711 SmallString<128> seqMemsJsonPath(metadataDir);
712 llvm::sys::path::append(seqMemsJsonPath,
"seq_mems.json");
713 emit::FileOp::create(builder, seqMemsJsonPath, [&] {
714 sv::VerbatimOp::create(builder, dutJsonBuffer, ValueRange{},
715 builder.getArrayAttr(jsonSymbols));
720 if (replSeqMemFile.empty()) {
721 emitError(circuitOp->getLoc())
722 <<
"metadata emission failed, the option "
723 "`-repl-seq-mem-file=<filename>` is mandatory for specifying a "
724 "valid seq mem metadata file";
728 emit::FileOp::create(builder, replSeqMemFile, [&] {
729 sv::VerbatimOp::create(builder, seqMemConfStr, ValueRange{},
730 builder.getArrayAttr(seqMemSymbols));
744 StringRef &filename) {
749 if (error || !anno.
isClass(annoClass))
753 if (!filename.empty()) {
754 op->emitError(
"more than one ") << annoClass <<
" annotation attached";
760 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
762 op->emitError(annoClass) <<
" requires a filename";
768 filename = filenameAttr.getValue();
769 if (filename.empty()) {
770 op->emitError(annoClass) <<
" requires a non-empty filename";
779 return failure(error);
785CreateSiFiveMetadataPass::emitRetimeModulesMetadata(ObjectModelIR &omir) {
787 auto *context = &getContext();
795 if (filename.empty())
800 llvm::raw_string_ostream os(buffer);
801 llvm::json::OStream j(os, 2);
805 SmallVector<Attribute> symbols;
806 SmallString<3> placeholder;
808 for (
auto module : circuitOp.
getBodyBlock()->getOps<FModuleLike>()) {
816 j.value((
"{{" + Twine(index++) +
"}}").str());
817 symbols.push_back(SymbolRefAttr::get(module.getModuleNameAttr()));
818 omir.addRetimeModule(module);
823 auto builder = ImplicitLocOpBuilder::atBlockEnd(UnknownLoc::get(context),
824 circuitOp.getBodyBlock());
825 emit::FileOp::create(builder, filename, [&] {
826 sv::VerbatimOp::create(builder, builder.getStringAttr(buffer), ValueRange{},
827 builder.getArrayAttr(symbols));
835CreateSiFiveMetadataPass::emitSitestBlackboxMetadata(ObjectModelIR &omir) {
839 std::array<StringRef, 6> blackListedAnnos = {
843 auto *context = &getContext();
846 StringRef dutFilename, testFilename;
854 if (dutFilename.empty() && testFilename.empty())
860 SmallVector<StringRef> dutLibs;
861 SmallVector<StringRef> testLibs;
863 for (
auto extModule : circuitOp.
getBodyBlock()->getOps<FExtModuleOp>()) {
864 SmallVector<StringRef> libs;
868 if (!extModule.getDefname())
873 bool isBlacklistedBlackbox =
874 llvm::any_of(blackListedAnnos, [&](
auto blackListedAnno) {
875 return annos.hasAnnotation(blackListedAnno);
878 if (!isBlacklistedBlackbox)
879 libs.push_back(*extModule.getDefname());
882 if (
auto libsAttr = libsAnno.getMember<ArrayAttr>(
"libraries")) {
883 for (
auto lib : libsAttr) {
884 if (
auto libStr = dyn_cast<StringAttr>(lib)) {
885 libs.push_back(libStr.getValue());
897 for (StringRef lib : libs)
898 dutLibs.push_back(lib);
900 for (StringRef lib : libs)
901 testLibs.push_back(lib);
903 omir.addBlackBoxModule(extModule, inDut, libs);
907 auto createOutput = [&](SmallVectorImpl<StringRef> &names,
908 StringRef filename) {
909 if (filename.empty())
913 std::sort(names.begin(), names.end());
914 names.erase(std::unique(names.begin(), names.end()), names.end());
919 llvm::raw_string_ostream os(buffer);
920 llvm::json::OStream j(os, 2);
922 for (
auto &name : names)
927 auto builder = ImplicitLocOpBuilder::atBlockEnd(UnknownLoc::get(context),
928 circuitOp.getBodyBlock());
930 emit::FileOp::create(builder, filename, [&] {
931 emit::VerbatimOp::create(builder, StringAttr::get(context, buffer));
935 createOutput(testLibs, testFilename);
936 createOutput(dutLibs, dutFilename);
941void CreateSiFiveMetadataPass::runOnOperation() {
942 auto circuits = getOperation().getOps<CircuitOp>();
943 if (circuits.empty())
946 circuitOp = *circuits.begin();
948 if (!llvm::hasSingleElement(circuits)) {
949 mlir::emitError(circuitOp.getLoc(),
950 "cannot process multiple circuit operations")
951 .attachNote((*std::next(circuits.begin())).getLoc())
952 <<
"second circuit here";
953 return signalPassFailure();
956 auto &instanceGraph = getAnalysis<InstanceGraph>();
957 instanceInfo = &getAnalysis<InstanceInfo>();
958 ObjectModelIR omir(circuitOp, instanceGraph, *instanceInfo, moduleNamespaces);
960 if (failed(emitRetimeModulesMetadata(omir)) ||
961 failed(emitSitestBlackboxMetadata(omir)) ||
962 failed(emitMemoryMetadata(omir)))
963 return signalPassFailure();
965 if (FModuleOp topMod = dyn_cast<FModuleOp>(*node->getModule()))
966 if (
auto objectOp = omir.instantiateSifiveMetadata(topMod)) {
967 auto portIndex = topMod.getNumPorts();
968 SmallVector<std::pair<unsigned, PortInfo>> ports = {
970 PortInfo(StringAttr::get(objectOp->getContext(),
"metadataObj"),
971 AnyRefType::get(objectOp->getContext()), Direction::Out)}};
972 topMod.insertPorts(ports);
973 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
974 topMod->getLoc(), topMod.getBodyBlock());
975 auto objectCast = ObjectAnyRefCastOp::create(builderOM, objectOp);
976 PropAssignOp::create(builderOM, topMod.getArgument(portIndex),
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Block * getBodyBlock(FModuleLike mod)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
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.
igraph::InstancePathCache InstancePathCache
constexpr const char * blackBoxAnnoClass
constexpr const char * sitestBlackBoxAnnoClass
constexpr const char * metadataDirectoryAttrName
constexpr const char * sitestBlackBoxLibrariesAnnoClass
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.
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 * retimeModuleAnnoClass
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 paths to module instances in the IR.