diff --git a/include/circt/Dialect/ESI/ESIStdServices.td b/include/circt/Dialect/ESI/ESIStdServices.td index 1bd034ba1c18..f4e494589304 100644 --- a/include/circt/Dialect/ESI/ESIStdServices.td +++ b/include/circt/Dialect/ESI/ESIStdServices.td @@ -102,3 +102,25 @@ def MMIOServiceDeclOp: ESI_Op<"service.std.mmio", std::optional<StringRef> getTypeName() { return "esi.service.std.mmio"; } }]; } + +def HostMemServiceDeclOp: ESI_Op<"service.std.hostmem", + [HasParent<"::mlir::ModuleOp">, Symbol, + DeclareOpInterfaceMethods<ServiceDeclOpInterface>]> { + let summary = "Host memory service"; + let description = [{ + Declares a service to read/write host memory. Used for DMA services. Must be + implemented by a BSP. + }]; + + let arguments = (ins SymbolNameAttr:$sym_name); + + let assemblyFormat = [{ + $sym_name attr-dict + }]; + + let extraClassDeclaration = [{ + ServicePortInfo readPortInfo(); + ServicePortInfo writePortInfo(); + std::optional<StringRef> getTypeName() { return "esi.service.std.hostmem"; } + }]; +} diff --git a/lib/Dialect/ESI/ESIStdServices.cpp b/lib/Dialect/ESI/ESIStdServices.cpp index c5b4dba24742..6eb2ca06ee4b 100644 --- a/lib/Dialect/ESI/ESIStdServices.cpp +++ b/lib/Dialect/ESI/ESIStdServices.cpp @@ -131,3 +131,56 @@ void MMIOServiceDeclOp::getPortList(SmallVectorImpl<ServicePortInfo> &ports) { ChannelType::get(ctxt, IntegerType::get(ctxt, 64))}}, /*resettable=*/UnitAttr())}); } + +ServicePortInfo HostMemServiceDeclOp::writePortInfo() { + auto *ctxt = getContext(); + auto addressType = + IntegerType::get(ctxt, 64, IntegerType::SignednessSemantics::Unsigned); + + // Write port + hw::StructType writeType = hw::StructType::get( + ctxt, + {hw::StructType::FieldInfo{StringAttr::get(ctxt, "address"), addressType}, + hw::StructType::FieldInfo{ + StringAttr::get(ctxt, "tag"), + IntegerType::get(ctxt, 8, + IntegerType::SignednessSemantics::Unsigned)}, + hw::StructType::FieldInfo{StringAttr::get(ctxt, "data"), + AnyType::get(ctxt)}}); + return createReqResp( + getSymNameAttr(), "write", "req", writeType, "ackTag", + IntegerType::get(ctxt, 8, IntegerType::SignednessSemantics::Unsigned)); +} + +ServicePortInfo HostMemServiceDeclOp::readPortInfo() { + auto *ctxt = getContext(); + auto addressType = + IntegerType::get(ctxt, 64, IntegerType::SignednessSemantics::Unsigned); + + hw::StructType readReqType = hw::StructType::get( + ctxt, { + hw::StructType::FieldInfo{StringAttr::get(ctxt, "address"), + addressType}, + hw::StructType::FieldInfo{ + StringAttr::get(ctxt, "tag"), + IntegerType::get( + ctxt, 8, IntegerType::SignednessSemantics::Unsigned)}, + }); + hw::StructType readRespType = hw::StructType::get( + ctxt, { + hw::StructType::FieldInfo{ + StringAttr::get(ctxt, "tag"), + IntegerType::get( + ctxt, 8, IntegerType::SignednessSemantics::Unsigned)}, + hw::StructType::FieldInfo{StringAttr::get(ctxt, "data"), + AnyType::get(ctxt)}, + }); + return createReqResp(getSymNameAttr(), "read", "req", readReqType, "resp", + readRespType); +} + +void HostMemServiceDeclOp::getPortList( + SmallVectorImpl<ServicePortInfo> &ports) { + ports.push_back(writePortInfo()); + ports.push_back(readPortInfo()); +} diff --git a/test/Dialect/ESI/services.mlir b/test/Dialect/ESI/services.mlir index 6915b14981f7..31c6713bba1f 100644 --- a/test/Dialect/ESI/services.mlir +++ b/test/Dialect/ESI/services.mlir @@ -227,3 +227,25 @@ hw.module @MMIOManifest(in %clk: !seq.clock, in %rst: i1) { %dataChannel, %dataChannelReady = esi.wrap.vr %data, %valid: i64 %cmdChannel = esi.bundle.unpack %dataChannel from %reqRW : !mmioRWReq } + +// CONN-LABEL: esi.service.std.hostmem @hostmem +// CONN-LABEL: hw.module @HostmemRW(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!hw.struct<address: ui64, tag: ui8, data: i128>>, in %readAddress : !esi.channel<!hw.struct<address: ui64, tag: ui8>>, in %hostmemWrite : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8, data: i128>> from "req", !esi.channel<ui8> to "ackTag"]>, in %hostmemRead : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: i64>> to "resp"]>, out readData : !esi.channel<!hw.struct<tag: ui8, data: i64>>, out writeDone : !esi.channel<ui8>) { +// CONN-NEXT: esi.manifest.req #esi.appid<"hostmemWrite">, <@hostmem::@write> std "esi.service.std.hostmem", !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8, data: i128>> from "req", !esi.channel<ui8> to "ackTag"]> +// CONN-NEXT: %ackTag = esi.bundle.unpack %write from %hostmemWrite : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8, data: i128>> from "req", !esi.channel<ui8> to "ackTag"]> +// CONN-NEXT: esi.manifest.req #esi.appid<"hostmemRead">, <@hostmem::@read> std "esi.service.std.hostmem", !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: i64>> to "resp"]> +// CONN-NEXT: %resp = esi.bundle.unpack %readAddress from %hostmemRead : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: i64>> to "resp"]> +// CONN-NEXT: hw.output %resp, %ackTag : !esi.channel<!hw.struct<tag: ui8, data: i64>>, !esi.channel<ui8> + +esi.service.std.hostmem @hostmem +!hostmemReadReq = !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: i64>> to "resp"]> +!hostmemWriteReq = !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8, data: i128>> from "req", !esi.channel<ui8> to "ackTag"]> + +hw.module @HostmemRW(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!hw.struct<address: ui64, tag: ui8, data: i128>>, in %readAddress : !esi.channel<!hw.struct<address: ui64, tag: ui8>>, out readData : !esi.channel<!hw.struct<tag: ui8, data: i64>>, out writeDone : !esi.channel<ui8>) { + %writeBundle = esi.service.req <@hostmem::@write> (#esi.appid<"hostmemWrite">) : !hostmemWriteReq + %ackTag = esi.bundle.unpack %write from %writeBundle : !hostmemWriteReq + + %readBundle = esi.service.req <@hostmem::@read> (#esi.appid<"hostmemRead">) : !hostmemReadReq + %readData = esi.bundle.unpack %readAddress from %readBundle : !hostmemReadReq + + hw.output %readData, %ackTag: !esi.channel<!hw.struct<tag: ui8, data: i64>>, !esi.channel<ui8> +}