20#include "mlir/IR/Builders.h"
21#include "mlir/IR/BuiltinTypes.h"
22#include "mlir/IR/PatternMatch.h"
23#include "mlir/IR/SymbolTable.h"
32circt::esi::ChannelType ChannelBufferOp::channelType() {
33 return getOutput().getType();
36LogicalResult ChannelBufferOp::verify() {
37 if (getInput().getType().getInner() != getOutput().getType().getInner())
38 return emitOpError(
"input and output data types must match");
39 if (getOutput().getType().getDataDelay() != 0)
40 return emitOpError(
"currently only supports channels with zero data delay");
48LogicalResult SnoopValidReadyOp::verify() {
49 ChannelType type = getInput().getType();
50 if (type.getSignaling() != ChannelSignaling::ValidReady)
51 return emitOpError(
"only supports valid-ready signaling");
52 if (type.getInner() != getData().getType())
53 return emitOpError(
"input and output types must match");
57LogicalResult SnoopValidReadyOp::inferReturnTypes(
58 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
59 DictionaryAttr attrs, mlir::OpaqueProperties properties,
60 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
61 auto i1 = IntegerType::get(context, 1);
62 results.push_back(i1);
63 results.push_back(i1);
64 results.push_back(cast<ChannelType>(operands[0].getType()).getInner());
68LogicalResult SnoopTransactionOp::verify() {
69 ChannelType type = getInput().getType();
70 if (type.getInner() != getData().getType())
71 return emitOpError(
"input and output types must match");
75LogicalResult SnoopTransactionOp::inferReturnTypes(
76 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
77 DictionaryAttr attrs, mlir::OpaqueProperties properties,
78 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
79 auto i1 = IntegerType::get(context, 1);
80 results.push_back(i1);
81 results.push_back(cast<ChannelType>(operands[0].getType()).getInner());
89LogicalResult FIFOOp::verify() {
90 if (getOutput().getType().getInner() != getInput().getType().getInner())
91 return emitOpError(
"input and output types must match");
99circt::esi::ChannelType PipelineStageOp::channelType() {
100 return cast<circt::esi::ChannelType>(getInput().getType());
107ParseResult WrapValidReadyOp::parse(OpAsmParser &parser,
108 OperationState &result) {
109 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
111 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> opList;
112 Type innerOutputType;
113 if (parser.parseOperandList(opList, 2, OpAsmParser::Delimiter::None) ||
114 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
115 parser.parseType(innerOutputType))
118 auto boolType = parser.getBuilder().getI1Type();
120 ChannelType::get(parser.getBuilder().getContext(), innerOutputType);
121 result.addTypes({outputType, boolType});
122 if (parser.resolveOperands(opList, {innerOutputType, boolType},
123 inputOperandsLoc, result.operands))
128void WrapValidReadyOp::print(OpAsmPrinter &p) {
129 p <<
" " << getRawInput() <<
", " << getValid();
130 p.printOptionalAttrDict((*this)->getAttrs());
134void WrapValidReadyOp::build(OpBuilder &b, OperationState &state, Value data,
136 build(b, state, ChannelType::get(state.getContext(),
data.getType()),
137 b.getI1Type(), data, valid);
140LogicalResult WrapValidReadyOp::verify() {
141 mlir::TypedValue<ChannelType> chanOut = getChanOutput();
142 if (chanOut.getType().getSignaling() != ChannelSignaling::ValidReady)
143 return emitOpError(
"only supports valid-ready signaling");
144 if (failed(ChannelType::verifyChannel(chanOut)))
149ParseResult UnwrapValidReadyOp::parse(OpAsmParser &parser,
150 OperationState &result) {
151 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
153 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> opList;
155 if (parser.parseOperandList(opList, 2, OpAsmParser::Delimiter::None) ||
156 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
157 parser.parseType(outputType))
161 ChannelType::get(parser.getBuilder().getContext(), outputType);
163 auto boolType = parser.getBuilder().getI1Type();
165 result.addTypes({inputType.getInner(), boolType});
166 if (parser.resolveOperands(opList, {inputType, boolType}, inputOperandsLoc,
172void UnwrapValidReadyOp::print(OpAsmPrinter &p) {
173 p <<
" " << getChanInput() <<
", " << getReady();
174 p.printOptionalAttrDict((*this)->getAttrs());
175 p <<
" : " << getRawOutput().getType();
178LogicalResult UnwrapValidReadyOp::verify() {
179 if (getChanInput().getType().getSignaling() != ChannelSignaling::ValidReady)
180 return emitOpError(
"only supports valid-ready signaling");
184circt::esi::ChannelType WrapValidReadyOp::channelType() {
185 return cast<circt::esi::ChannelType>(getChanOutput().getType());
188void UnwrapValidReadyOp::build(OpBuilder &b, OperationState &state,
189 Value inChan, Value ready) {
190 auto inChanType = cast<ChannelType>(inChan.getType());
191 build(b, state, inChanType.getInner(), b.getI1Type(), inChan, ready);
194circt::esi::ChannelType UnwrapValidReadyOp::channelType() {
195 return cast<circt::esi::ChannelType>(getChanInput().getType());
198circt::esi::ChannelType WrapFIFOOp::channelType() {
199 return cast<circt::esi::ChannelType>(getChanOutput().getType());
203 Type &chanInputType) {
204 auto loc = p.getCurrentLocation();
206 if (p.parseType(chType))
208 if (chType.getSignaling() != ChannelSignaling::FIFO)
209 return p.emitError(loc,
"can only wrap into FIFO type");
210 dataType = chType.getInner();
211 chanInputType = chType;
220LogicalResult WrapFIFOOp::verify() {
221 if (getChanOutput().getType().getSignaling() != ChannelSignaling::FIFO)
222 return emitOpError(
"only supports FIFO signaling");
226circt::esi::ChannelType UnwrapFIFOOp::channelType() {
227 return cast<circt::esi::ChannelType>(getChanInput().getType());
230LogicalResult UnwrapFIFOOp::verify() {
231 if (getChanInput().getType().getSignaling() != ChannelSignaling::FIFO)
232 return emitOpError(
"only supports FIFO signaling");
237UnwrapFIFOOp::inferReturnTypes(MLIRContext *context, std::optional<Location>,
238 ValueRange operands, DictionaryAttr,
239 mlir::OpaqueProperties, mlir::RegionRange,
240 SmallVectorImpl<Type> &inferredResulTypes) {
241 inferredResulTypes.push_back(
242 cast<ChannelType>(operands[0].getType()).getInner());
243 inferredResulTypes.push_back(
244 IntegerType::get(context, 1, IntegerType::Signless));
251 if (!iface.lookupSymbol<InterfaceSignalOp>(
"valid"))
253 if (!iface.lookupSymbol<InterfaceSignalOp>(
"ready"))
255 auto dataSig = iface.lookupSymbol<InterfaceSignalOp>(
"data");
258 return dataSig.getType();
265 circt::sv::ModportType modportType,
266 ChannelType chanType) {
268 SymbolTable::lookupNearestSymbolFrom<circt::sv::InterfaceModportOp>(
269 op, modportType.getModport());
271 return op->emitError(
"Could not find modport ")
272 << modportType.getModport() <<
" in symbol table.";
273 auto iface = cast<circt::sv::InterfaceOp>(modport->getParentOp());
276 return op->emitOpError(
"Interface is not a valid ESI interface.");
277 if (esiDataType != chanType.getInner())
278 return op->emitOpError(
"Operation specifies ")
279 << chanType <<
" but type inside doesn't match interface data type "
280 << esiDataType <<
".";
284LogicalResult WrapSVInterfaceOp::verify() {
285 auto modportType = cast<circt::sv::ModportType>(getInterfaceSink().getType());
286 auto chanType = cast<ChannelType>(getOutput().getType());
290circt::esi::ChannelType WrapSVInterfaceOp::channelType() {
291 return cast<circt::esi::ChannelType>(getOutput().getType());
294LogicalResult UnwrapSVInterfaceOp::verify() {
296 cast<circt::sv::ModportType>(getInterfaceSource().getType());
297 auto chanType = cast<ChannelType>(getChanInput().getType());
301circt::esi::ChannelType UnwrapSVInterfaceOp::channelType() {
302 return cast<circt::esi::ChannelType>(getChanInput().getType());
305LogicalResult WrapWindow::verify() {
306 hw::UnionType expectedInput = getWindow().getType().getLoweredType();
307 if (expectedInput == getFrame().getType())
309 return emitOpError(
"Expected input type is ") << expectedInput;
313UnwrapWindow::inferReturnTypes(MLIRContext *, std::optional<Location>,
314 ValueRange operands, DictionaryAttr,
315 mlir::OpaqueProperties, mlir::RegionRange,
316 SmallVectorImpl<Type> &inferredReturnTypes) {
317 auto windowType = cast<WindowType>(operands.front().getType());
318 inferredReturnTypes.push_back(windowType.getLoweredType());
325 if (p.parseType(window))
328 frame = window.getLoweredType();
341LogicalResult CosimFromHostEndpointOp::verify() {
342 ChannelType chanType = getFromHost().getType();
343 if (chanType.getSignaling() != ChannelSignaling::ValidReady)
344 return emitOpError(
"only supports valid-ready signaling");
348LogicalResult CosimToHostEndpointOp::verify() {
349 ChannelType chanType = getToHost().getType();
350 if (chanType.getSignaling() != ChannelSignaling::ValidReady)
351 return emitOpError(
"only supports valid-ready signaling");
360static FailureOr<ServiceDeclOpInterface>
362 hw::InnerRefAttr servicePort) {
363 ModuleOp top = op->getParentOfType<mlir::ModuleOp>();
364 SymbolTable &topSyms = symbolTable.getSymbolTable(top);
366 StringAttr modName = servicePort.getModule();
367 auto serviceDecl = topSyms.lookup<ServiceDeclOpInterface>(modName);
369 return op->emitOpError(
"Could not find service declaration ")
370 << servicePort.getModuleRef();
375static FailureOr<ServicePortInfo>
377 hw::InnerRefAttr servicePort) {
379 if (failed(serviceDecl))
381 auto portInfo = serviceDecl->getPortInfo(servicePort.getName());
382 if (failed(portInfo))
383 return op->emitOpError(
"Could not locate port ") << servicePort.getName();
392 if (expected == actual)
396 return TypeSwitch<Type, LogicalResult>(expected)
398 .Case<AnyType>([&](Type) {
return success(); })
400 .Case<ChannelType>([&](ChannelType expectedChannel) {
401 auto actualChannel = dyn_cast<ChannelType>(actual);
405 actualChannel.getInner());
408 .Case<hw::StructType>([&](hw::StructType expectedStruct) {
409 auto actualStruct = dyn_cast<hw::StructType>(actual);
412 auto expectedFields = expectedStruct.getElements();
413 auto actualFields = actualStruct.getElements();
414 if (expectedFields.size() != actualFields.size())
416 for (
auto [efield, afield] : llvm::zip(expectedFields, actualFields)) {
417 if (efield.name != afield.name)
425 .Case<hw::ArrayType>([&](hw::ArrayType expectedArray) {
426 auto actualArray = dyn_cast<hw::ArrayType>(actual);
429 if (expectedArray.getNumElements() != actualArray.getNumElements())
432 actualArray.getElementType());
435 .Case<hw::UnionType>([&](hw::UnionType expectedUnion) {
436 auto actualUnion = dyn_cast<hw::UnionType>(actual);
439 auto expectedElements = expectedUnion.getElements();
440 auto actualElements = actualUnion.getElements();
441 if (expectedElements.size() != actualElements.size())
443 for (
auto [efield, afield] :
444 llvm::zip(expectedElements, actualElements)) {
445 if (efield.name != afield.name)
447 if (efield.offset != afield.offset)
455 .Case<ListType>([&](ListType expectedList) {
456 auto actualList = dyn_cast<ListType>(actual);
460 actualList.getElementType());
463 .Case<WindowType>([&](WindowType expectedWindow) {
464 auto actualWindow = dyn_cast<WindowType>(actual);
468 actualWindow.getInto());
471 .Case<hw::TypeAliasType>([&](hw::TypeAliasType expectedAlias) {
472 auto actualAlias = dyn_cast<hw::TypeAliasType>(actual);
476 actualAlias.getCanonicalType());
479 .Default([&](Type) {
return failure(); });
485 ChannelBundleType svcBundleType,
486 ChannelBundleType reqBundleType,
487 bool skipDirectionCheck) {
488 if (svcBundleType.getChannels().size() != reqBundleType.getChannels().size())
489 return req->emitOpError(
490 "Request port bundle channel count does not match service "
491 "port bundle channel count");
494 DenseMap<StringAttr, BundledChannel> declBundleChannels;
496 declBundleChannels[bc.name] = bc;
500 auto f = declBundleChannels.find(bc.name);
501 if (f == declBundleChannels.end())
502 return req->emitOpError(
503 "Request channel name not found in service port bundle");
504 if (!skipDirectionCheck && f->second.direction != bc.direction)
505 return req->emitOpError(
506 "Request channel direction does not match service "
507 "port bundle channel direction");
510 return req->emitOpError(
511 "Request channel type does not match service port "
512 "bundle channel type")
514 <<
"Service port '" << bc.name.getValue()
515 <<
"' type: " << f->second.type;
524RequestConnectionOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
532LogicalResult ServiceImplementConnReqOp::verifySymbolUses(
533 SymbolTableCollection &symbolTable) {
541void CustomServiceDeclOp::getPortList(SmallVectorImpl<ServicePortInfo> &ports) {
542 for (
auto toClient : getOps<ServiceDeclPortOp>())
544 hw::InnerRefAttr::
get(getSymNameAttr(), toClient.getInnerSymAttr()),
545 toClient.getToClientType()});
554 SmallVectorImpl<Type> &toChannelTypes,
555 SmallVectorImpl<Type> &fromChannelTypes, Type &type) {
557 ChannelBundleType bundleType;
558 if (parser.parseType(bundleType))
563 if (ch.direction == ChannelDirection::to)
564 toChannelTypes.push_back(ch.type);
565 else if (ch.direction == ChannelDirection::from)
566 fromChannelTypes.push_back(ch.type);
568 assert(
false &&
"Channel direction invalid");
571template <
typename T3,
typename T4>
574 p.printType(bundleType);
576void UnpackBundleOp::build(::mlir::OpBuilder &odsBuilder,
577 ::mlir::OperationState &odsState, Value bundle,
578 mlir::ValueRange fromChannels) {
580 cast<ChannelBundleType>(bundle.getType()).getChannels())
581 if (ch.direction == ChannelDirection::to)
582 odsState.addTypes(ch.type);
583 odsState.addOperands(bundle);
584 odsState.addOperands(fromChannels);
587LogicalResult PackBundleOp::verify() {
588 if (!getBundle().hasOneUse()) {
589 if (getBundle().getUsers().
empty())
590 return emitOpError(
"bundle must be used");
591 return emitOpError(
"bundle must only be used once");
595void PackBundleOp::build(::mlir::OpBuilder &odsBuilder,
596 ::mlir::OperationState &odsState,
597 ChannelBundleType bundleType,
598 mlir::ValueRange toChannels) {
599 odsState.addTypes(bundleType);
600 for (
BundledChannel ch : cast<ChannelBundleType>(bundleType).getChannels())
601 if (ch.direction == ChannelDirection::from)
602 odsState.addTypes(ch.type);
603 odsState.addOperands(toChannels);
606LogicalResult UnpackBundleOp::verify() {
607 if (!getBundle().hasOneUse()) {
608 if (getBundle().getUsers().
empty())
609 return emitOpError(
"bundle must be used");
610 return emitOpError(
"bundle must only be used once");
616 if (getNumResults() == 0)
618 setNameFn(getResult(0),
"bundle");
619 for (
auto [idx, from] :
llvm::enumerate(
llvm::make_filter_range(
621 return ch.direction == ChannelDirection::from;
623 if (idx + 1 < getNumResults())
624 setNameFn(getResult(idx + 1), from.name.getValue());
628 for (
auto [idx, to] :
llvm::enumerate(
llvm::make_filter_range(
630 return ch.direction == ChannelDirection::to;
632 if (idx < getNumResults())
633 setNameFn(getResult(idx), to.name.getValue());
639LogicalResult ESIPureModuleOp::verify() {
640 ESIDialect *esiDialect = getContext()->getLoadedDialect<ESIDialect>();
641 Block &body = getBody().front();
642 auto channelOrOutput = [](Value v) {
643 if (isa<ChannelType, ChannelBundleType>(v.getType()))
645 if (v.getUsers().empty())
647 return llvm::all_of(v.getUsers(), [](Operation *op) {
648 return isa<ESIPureModuleOutputOp>(op);
652 DenseMap<StringAttr, std::tuple<hw::ModulePort::Direction, Type, Operation *>>
654 for (Operation &op : body.getOperations()) {
655 if (igraph::InstanceOpInterface inst =
656 dyn_cast<igraph::InstanceOpInterface>(op)) {
657 if (llvm::any_of(op.getOperands(), [](Value v) {
658 return !(isa<ChannelType, ChannelBundleType>(v.getType()) ||
659 isa<ESIPureModuleInputOp>(v.getDefiningOp()));
661 return inst.emitOpError(
662 "instances in ESI pure modules can only contain channel ports or "
663 "ports driven by 'input' ops");
664 if (!llvm::all_of(op.getResults(), channelOrOutput))
665 return inst.emitOpError(
666 "instances in ESI pure modules can only contain channel ports or "
667 "drive only 'outputs'");
670 if (op.getDialect() != esiDialect)
671 return op.emitOpError(
"operation not allowed in ESI pure modules");
675 if (
auto port = dyn_cast<ESIPureModuleInputOp>(op)) {
676 auto existing = ports.find(port.getNameAttr());
677 Type portType = port.getResult().getType();
678 if (existing != ports.end()) {
679 auto [dir, type, op] = existing->getSecond();
680 if (dir != hw::ModulePort::Direction::Input || type != portType)
681 return (port.emitOpError(
"port '")
682 << port.getName() <<
"' previously declared as type " << type)
683 .attachNote(op->getLoc());
685 ports[port.getNameAttr()] = std::make_tuple(
686 hw::ModulePort::Direction::Input, portType, port.getOperation());
687 }
else if (
auto port = dyn_cast<ESIPureModuleOutputOp>(op)) {
688 auto existing = ports.find(port.getNameAttr());
689 if (existing != ports.end())
690 return (port.emitOpError(
"port '")
691 << port.getName() <<
"' previously declared")
692 .attachNote(std::get<2>(existing->getSecond())->getLoc());
693 ports[port.getNameAttr()] =
694 std::make_tuple(hw::ModulePort::Direction::Input,
695 port.getValue().getType(), port.getOperation());
701hw::ModuleType ESIPureModuleOp::getHWModuleType() {
702 return hw::ModuleType::get(getContext(), {});
705SmallVector<::circt::hw::PortInfo> ESIPureModuleOp::getPortList() {
return {}; }
707 ::llvm::report_fatal_error(
"not supported");
710size_t ESIPureModuleOp::getNumPorts() {
return 0; }
711size_t ESIPureModuleOp::getNumInputPorts() {
return 0; }
712size_t ESIPureModuleOp::getNumOutputPorts() {
return 0; }
713size_t ESIPureModuleOp::getPortIdForInputId(
size_t) {
714 assert(0 &&
"Out of bounds input port id");
717size_t ESIPureModuleOp::getPortIdForOutputId(
size_t) {
718 assert(0 &&
"Out of bounds output port id");
722SmallVector<Location> ESIPureModuleOp::getAllPortLocs() {
723 SmallVector<Location> retval;
727void ESIPureModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
728 emitError(
"No ports for port locations");
731void ESIPureModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
732 emitError(
"No ports for port naming");
735void ESIPureModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
736 emitError(
"No ports for port attributes");
739void ESIPureModuleOp::removeAllPortAttrs() {
740 emitError(
"No ports for port attributes)");
743ArrayRef<Attribute> ESIPureModuleOp::getAllPortAttrs() {
return {}; }
745void ESIPureModuleOp::setHWModuleType(hw::ModuleType type) {
746 emitError(
"No ports for port types");
753StringRef ServiceImplRecordOp::getManifestClass() {
754 return getIsEngine() ?
"engine" :
"service";
757void ServiceImplRecordOp::getDetails(SmallVectorImpl<NamedAttribute> &results) {
758 auto *
ctxt = getContext();
760 results.emplace_back(getAppIDAttrName(), getAppIDAttr());
762 results.emplace_back(getServiceAttrName(), getServiceAttr());
763 results.emplace_back(getServiceImplNameAttrName(), getServiceImplNameAttr());
765 for (
auto implDetail : getImplDetailsAttr().getValue())
766 results.push_back(implDetail);
769 SmallVector<Attribute, 8> reqDetails;
770 for (
auto reqDetail : getReqDetails().front().getOps<IsManifestData>())
771 reqDetails.push_back(reqDetail.getDetailsAsDict());
772 results.emplace_back(StringAttr::get(ctxt,
"clientDetails"),
773 ArrayAttr::get(ctxt, reqDetails));
777 Region &reqDetailsRegion) {
778 parser.parseOptionalRegion(reqDetailsRegion);
779 if (reqDetailsRegion.empty())
780 reqDetailsRegion.emplaceBlock();
785 Region &reqDetailsRegion) {
786 if (!reqDetailsRegion.empty() && !reqDetailsRegion.front().empty())
787 p.printRegion(reqDetailsRegion,
false,
791StringRef ServiceImplClientRecordOp::getManifestClass() {
792 return "serviceClient";
794void ServiceImplClientRecordOp::getDetails(
795 SmallVectorImpl<NamedAttribute> &results) {
799 results.emplace_back(getRelAppIDPathAttrName(), getRelAppIDPathAttr());
800 auto servicePort = getServicePortAttr();
801 results.emplace_back(
802 getServicePortAttrName(),
806 NamedAttribute(StringAttr::get(getContext(),
"serviceName"),
807 FlatSymbolRefAttr::get(servicePort.getModule())),
808 NamedAttribute(StringAttr::get(getContext(),
"port"),
809 servicePort.getName()),
811 if (
const auto &channelAssignments = getChannelAssignments())
813 NamedAttribute(getChannelAssignmentsAttrName(), *channelAssignments));
815 if (
const auto &implDetails = getImplDetails())
816 for (
const auto &implDetail : *implDetails)
817 results.push_back(implDetail);
820StringRef ServiceRequestRecordOp::getManifestClass() {
return "clientPort"; }
822void ServiceRequestRecordOp::getDetails(
823 SmallVectorImpl<NamedAttribute> &results) {
824 auto *
ctxt = getContext();
825 results.emplace_back(StringAttr::get(ctxt,
"appID"), getRequestorAttr());
826 results.emplace_back(getTypeIDAttrName(), getTypeIDAttr());
827 auto servicePort = getServicePortAttr();
828 results.emplace_back(
829 getServicePortAttrName(),
833 NamedAttribute(StringAttr::get(getContext(),
"serviceName"),
834 FlatSymbolRefAttr::get(servicePort.getModule())),
835 NamedAttribute(StringAttr::get(getContext(),
"port"),
836 servicePort.getName()),
840StringRef SymbolMetadataOp::getManifestClass() {
return "symInfo"; }
842StringRef SymbolConstantsOp::getManifestClass() {
return "symConsts"; }
843void SymbolConstantsOp::getDetails(SmallVectorImpl<NamedAttribute> &results) {
844 for (
auto &attr : getConstantsAttr())
845 results.push_back(attr);
848#define GET_OP_CLASSES
849#include "circt/Dialect/ESI/ESI.cpp.inc"
851#include "circt/Dialect/ESI/ESIInterfaces.cpp.inc"
assert(baseType &&"element must be base type")
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static FailureOr< ServiceDeclOpInterface > getServiceDecl(Operation *op, SymbolTableCollection &symbolTable, hw::InnerRefAttr servicePort)
Get the port declaration op for the specified service decl, port name.
static bool parseInferWindowRet(OpAsmParser &p, Type &frame, Type &windowOut)
Determine the input type ('frame') from the return type ('window').
ParseResult parseWrapFIFOType(OpAsmParser &p, Type &dataType, Type &chanInputType)
static LogicalResult verifySVInterface(Operation *op, circt::sv::ModportType modportType, ChannelType chanType)
Verify that the modport type of 'modportArg' points to an interface which looks like an ESI interface...
void printServiceImplRecordReqDetails(OpAsmPrinter &p, ServiceImplRecordOp, Region &reqDetailsRegion)
static Type getEsiDataType(circt::sv::InterfaceOp iface)
If 'iface' looks like an ESI interface, return the inner data type.
static FailureOr< ServicePortInfo > getServicePortInfo(Operation *op, SymbolTableCollection &symbolTable, hw::InnerRefAttr servicePort)
Get the port info for the specified service decl and port name.
static void printUnPackBundleType(OpAsmPrinter &p, Operation *, T3, T4, Type bundleType)
static ParseResult parseUnPackBundleType(OpAsmParser &parser, SmallVectorImpl< Type > &toChannelTypes, SmallVectorImpl< Type > &fromChannelTypes, Type &type)
static void printInferWindowRet(OpAsmPrinter &p, Operation *, Type, Type window)
void printWrapFIFOType(OpAsmPrinter &p, WrapFIFOOp wrap, Type dataType, Type chanType)
bool parseServiceImplRecordReqDetails(OpAsmParser &parser, Region &reqDetailsRegion)
static InstancePath empty
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
LogicalResult checkBundleTypeMatch(Operation *req, ChannelBundleType svcBundleType, ChannelBundleType reqBundleType, bool skipDirectionCheck)
Check that the channels on two bundles match allowing for AnyType in the 'svc' bundle.
LogicalResult checkInnerTypeMatch(Type expected, Type actual)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Describes a service port.
This holds the name, type, direction of a module's ports.