Skip to content

Commit

Permalink
[ESI] Compressed manifest lowering for cosim (#6358)
Browse files Browse the repository at this point in the history
CompressedModuleOp lowers to an instance of the Cosim_Manifest external module.
  • Loading branch information
teqdruid authored Oct 31, 2023
1 parent 6ef2489 commit bae95f5
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 2 deletions.
6 changes: 6 additions & 0 deletions include/circt/Dialect/ESI/ESIPasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
namespace circt {
namespace esi {

/// This should eventually become a set of functions to define the various
/// platform-specific lowerings.
struct Platform {
static constexpr char cosim[] = "cosim";
};

std::unique_ptr<OperationPass<ModuleOp>> createESIPhysicalLoweringPass();
std::unique_ptr<OperationPass<ModuleOp>> createESIBundleLoweringPass();
std::unique_ptr<OperationPass<ModuleOp>> createESIPortLoweringPass();
Expand Down
4 changes: 4 additions & 0 deletions include/circt/Dialect/ESI/ESIPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ def LowerESItoHW: Pass<"lower-esi-to-hw", "mlir::ModuleOp"> {
let summary = "Lower ESI to HW where possible and SV elsewhere.";
let constructor = "circt::esi::createESItoHWPass()";
let dependentDialects = ["circt::comb::CombDialect", "circt::hw::HWDialect"];
let options = [
Option<"platform", "platform", "std::string",
"", "Target this platform">
];
}

#endif // CIRCT_DIALECT_ESI_ESIPASSES_TD
4 changes: 4 additions & 0 deletions lib/Dialect/ESI/Passes/ESIBuildManifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ void ESIBuildManifestPass::runOnOperation() {
ctxt, "esi_system_manifest.json.zlib");
compressedVerbatim->setAttr("output_file", compressedOutputFileAttr);

b.setInsertionPoint(symCache.getDefinition(appidRoot.getTopModuleRefAttr())
->getRegion(0)
.front()
.getTerminator());
b.create<CompressedManifestOp>(
b.getUnknownLoc(),
BlobAttr::get(ctxt, ArrayRef<char>(reinterpret_cast<char *>(
Expand Down
64 changes: 64 additions & 0 deletions lib/Dialect/ESI/Passes/ESILowerToHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,65 @@ CosimLowering::matchAndRewrite(CosimEndpointOp ep, OpAdaptor adaptor,
return success();
}

namespace {
/// Lower `CompressedManifestOps` ops to a SystemVerilog extern module.
struct CosimManifestLowering
: public OpConversionPattern<CompressedManifestOp> {
public:
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(CompressedManifestOp, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const final;
};
} // anonymous namespace

LogicalResult CosimManifestLowering::matchAndRewrite(
CompressedManifestOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const {
MLIRContext *ctxt = rewriter.getContext();

// Declare external module.
Attribute params[] = {
ParamDeclAttr::get("COMPRESSED_MANIFEST_SIZE", rewriter.getI32Type())};
PortInfo ports[] = {
{{rewriter.getStringAttr("compressed_manifest"),
rewriter.getType<hw::UnpackedArrayType>(
rewriter.getI8Type(),
ParamDeclRefAttr::get(
rewriter.getStringAttr("COMPRESSED_MANIFEST_SIZE"),
rewriter.getI32Type())),
ModulePort::Direction::Input},
0},
};
rewriter.setInsertionPointToEnd(
op->getParentOfType<mlir::ModuleOp>().getBody());
auto manifestModule = rewriter.create<HWModuleExternOp>(
op.getLoc(), rewriter.getStringAttr("Cosim_Manifest"), ports,
"Cosim_Manifest", ArrayAttr::get(ctxt, params));

rewriter.setInsertionPoint(op);

// Assemble the manifest data into a constant.
SmallVector<Attribute> bytes;
for (char b : op.getCompressedManifest().getData())
bytes.push_back(rewriter.getI8IntegerAttr(b));
auto manifestConstant = rewriter.create<hw::AggregateConstantOp>(
op.getLoc(),
hw::UnpackedArrayType::get(rewriter.getI8Type(), bytes.size()),
rewriter.getArrayAttr(bytes));

// Then instantiate the external module.
rewriter.create<hw::InstanceOp>(
op.getLoc(), manifestModule, "__manifest",
ArrayRef<Value>({manifestConstant}),
rewriter.getArrayAttr(
{ParamDeclAttr::get("COMPRESSED_MANIFEST_SIZE",
rewriter.getI32IntegerAttr(bytes.size()))}));
rewriter.eraseOp(op);
return success();
}

void ESItoHWPass::runOnOperation() {
auto top = getOperation();
auto *ctxt = &getContext();
Expand All @@ -427,6 +486,7 @@ void ESItoHWPass::runOnOperation() {

pass1Target.addIllegalOp<WrapSVInterfaceOp, UnwrapSVInterfaceOp>();
pass1Target.addIllegalOp<PipelineStageOp>();
pass1Target.addIllegalOp<CompressedManifestOp>();

// Add all the conversion patterns.
ESIHWBuilder esiBuilder(top);
Expand All @@ -437,6 +497,10 @@ void ESItoHWPass::runOnOperation() {
pass1Patterns.insert<CosimLowering>(esiBuilder);
pass1Patterns.insert<NullSourceOpLowering>(ctxt);

if (platform == Platform::cosim) {
pass1Patterns.insert<CosimManifestLowering>(ctxt);
}

// Run the conversion.
if (failed(
applyPartialConversion(top, pass1Target, std::move(pass1Patterns))))
Expand Down
10 changes: 8 additions & 2 deletions test/Dialect/ESI/manifest.mlir
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// REQUIRES: zlib
// RUN: circt-opt %s --esi-connect-services --esi-appid-hier=top=top --esi-build-manifest="top=top to-file=%t1.json" | circt-opt | FileCheck --check-prefix=HIER %s
// RUN: circt-opt %s --esi-connect-services --esi-appid-hier=top=top --esi-build-manifest="top=top to-file=%t1.json" > %t1.mlir
// RUN: circt-opt %t1.mlir | FileCheck --check-prefix=HIER %s
// RUN: FileCheck --input-file=%t1.json %s
// RUN: circt-opt %t1.mlir --esi-clean-metadata --lower-esi-bundles --lower-esi-ports --lower-esi-to-hw=platform=cosim | FileCheck --check-prefix=HW %s

hw.type_scope @__hw_typedecls {
hw.typedecl @foo, "Foo" : i1
Expand Down Expand Up @@ -30,6 +32,7 @@ hw.module @top(in %clk: !seq.clock, in %rst: i1) {
hw.instance "m2" @Loopback (clk: %clk: !seq.clock) -> () {esi.appid=#esi.appid<"loopback_inst"[1]>}
}

// HIER-LABEL: esi.manifest.compressed <"{{.+}}">
// HIER-LABEL: esi.manifest.hier_root @top {
// HIER: esi.manifest.service_impl #esi.appid<"cosim"> svc @HostComms by "cosim" with {} {
// HIER: esi.manifest.impl_conn [#esi.appid<"loopback_inst"[0]>, #esi.appid<"loopback_tohw">] req <@HostComms::@Recv>(!esi.bundle<[!esi.channel<i8> to "recv"]>) with {channel_assignments = {recv = "loopback_inst[0].loopback_tohw.recv"}}
Expand All @@ -46,7 +49,10 @@ hw.module @top(in %clk: !seq.clock, in %rst: i1) {
// HIER: esi.manifest.req #esi.appid<"loopback_fromhw">, <@HostComms::@Send>, toServer, !esi.bundle<[!esi.channel<i8> to "send"]>
// HIER: }
// HIER: }
// HIER-LABEL: esi.manifest.compressed <"{{.+}}">

// HW-LABEL: hw.module @top
// HW: hw.instance "__manifest" @Cosim_Manifest<COMPRESSED_MANIFEST_SIZE: i32 = 774>(compressed_manifest: %{{.+}}: !hw.uarray<774xi8>) -> ()
// HW-LABEL: hw.module.extern @Cosim_Manifest<COMPRESSED_MANIFEST_SIZE: i32>(in %compressed_manifest : !hw.uarray<#hw.param.decl.ref<"COMPRESSED_MANIFEST_SIZE">xi8>) attributes {verilogName = "Cosim_Manifest"}

// CHECK: {
// CHECK-LABEL: "api_version": 1,
Expand Down

0 comments on commit bae95f5

Please sign in to comment.