Program Listing for File EmitHLSToKriaDtsi.cpp

↰ Return to documentation for file (lib/Target/EmitHLSToKriaDtsi/EmitHLSToKriaDtsi.cpp)

// Implementation of translation EmitHLSToKriaDtsi
//
// @file
// @author     Jiahong Bi (jiahong.bi@tu-dresden.de)

#include "laksa-mlir/Dialect/EmitHLS/IR/EmitHLS.h"
#include "laksa-mlir/Target/EmitHLSToKriaDtsi/KriaDtsiEmitter.h"

#include "llvm/Support/CommandLine.h"

using namespace mlir;
using namespace mlir::emithls;

namespace {

// 0xa0000000 is the base address Vivado's address editor assigns by default
// to the first custom IP's AXI-Lite control interface (s_axi_control) when
// it is auto-connected to the Zynq MPSoC's M_AXI_HPM0_FPD master port, as
// done by the EmitHLSToVivadoTcl translation.
llvm::cl::opt<std::string> clKriaAxiLiteBaseAddress(
    "kria-axi-lite-base-address",
    llvm::cl::desc(
        "Physical base address of the HLS IP's AXI-Lite control interface, "
        "as assigned by Vivado's address editor"),
    llvm::cl::init("0xa0000000"));

llvm::cl::opt<std::string> clKriaAxiLiteSize(
    "kria-axi-lite-size",
    llvm::cl::desc(
        "Size of the AXI-Lite control register window, as assigned by "
        "Vivado's address editor"),
    llvm::cl::init("0x10000"));

} // namespace

// Finds the function marked as the design's top function, i.e. the one whose
// body contains a PragmaTopInterfaceOp. Its symbol name doubles as the
// device tree node's label and unit name.
static FailureOr<FuncOp> findTopFunc(ModuleOp moduleOp)
{
    FuncOp topFunc = nullptr;
    auto result = moduleOp.walk([&](PragmaTopInterfaceOp topInterfaceOp) {
        FuncOp funcOp = topInterfaceOp->getParentOfType<FuncOp>();
        if (!funcOp || topFunc) return WalkResult::interrupt();
        topFunc = funcOp;
        return WalkResult::advance();
    });
    if (result.wasInterrupted() || !topFunc)
        return moduleOp->emitError(
            "expected exactly one function containing a top_interface "
            "pragma");
    return topFunc;
}

// Strips a leading "0x"/"0X", if present, so the address can be reused as a
// device tree unit-address suffix (`node@<address>`).
static StringRef stripHexPrefix(StringRef hex)
{
    if (hex.starts_with_insensitive("0x")) return hex.drop_front(2);
    return hex;
}

//===----------------------------------------------------------------------===//
// Translation entry point
//===----------------------------------------------------------------------===//

LogicalResult emithls::translateEmitHLSToKriaDtsi(ModuleOp op, raw_ostream &os)
{
    FailureOr<FuncOp> topFunc = findTopFunc(op);
    if (failed(topFunc)) return failure();
    StringRef nodeName = topFunc->getSymName();
    StringRef unitAddress = stripHexPrefix(clKriaAxiLiteBaseAddress);

    os << "/dts-v1/;\n"
       << "/plugin/;\n"
          "\n"
          "/ {\n"
          "    fragment@0 {\n"
          "        target-path = \"/\";\n"
          "        __overlay__ {\n"
          "            #address-cells = <2>;\n"
          "            #size-cells = <2>;\n"
          "\n"
       << "            " << nodeName << ": " << nodeName << "@" << unitAddress
       << " {\n"
          "                compatible = \"tud,laksa\";\n"
          "                reg = <0x0 "
       << clKriaAxiLiteBaseAddress << " 0x0 " << clKriaAxiLiteSize
       << ">;\n"
          "            };\n"
          "        };\n"
          "    };\n"
          "};\n";

    return success();
}