diff --git a/include/circt-c/ImportVerilog.h b/include/circt-c/ImportVerilog.h new file mode 100644 index 000000000000..5621f94f1131 --- /dev/null +++ b/include/circt-c/ImportVerilog.h @@ -0,0 +1,84 @@ +//===-- circt-c/ImportVerilog.h - C API for importing Verilog -----*- C -*-===// +// +// This header declares the C interface for importing Verilog from Verilog +// source files. +// +//===----------------------------------------------------------------------===// + +#ifndef CIRCT_C_IMPORTVERILOG_H +#define CIRCT_C_IMPORTVERILOG_H + +#include "mlir-c/IR.h" +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum MlirImportVerilogMode { + MLIR_IMPORT_VERILOG_MODE_ONLY_LINT, + MLIR_IMPORT_VERILOG_MODE_ONLY_PARSE, + MLIR_IMPORT_VERILOG_MODE_FULL, +} MlirImportVerilogMode; + +typedef struct MlirImportVerilogOptions { + MlirImportVerilogMode mode; + bool debugInfo; + bool lowerAlwaysAtStarAsComb; + + // Include paths + const char **includeDirs; + size_t includeDirsNum; + const char **includeSystemDirs; + size_t includeSystemDirsNum; + const char **libDirs; + size_t libDirsNum; + const char **libExts; + size_t libExtsNum; + const char **excludeExts; + size_t excludeExtsNum; + const char **ignoreDirectives; + size_t ignoreDirectivesNum; + + // Preprocessing + uint32_t maxIncludeDepth; // UINT32_MAX for no limit + const char **defines; + size_t definesNum; + const char **undefines; + size_t undefinesNum; + bool librariesInheritMacros; + + // Compilation + const char *timeScale; // Optional + bool allowUseBeforeDeclare; + bool ignoreUnknownModules; + const char **topModules; + size_t topModulesNum; + const char **paramOverrides; + size_t paramOverridesNum; + + // Diagnostics Control + uint32_t errorLimit; // UINT32_MAX for no limit + const char **warningOptions; + size_t warningOptionsNum; + const char **suppressWarningsPaths; + size_t suppressWarningsPathsNum; + + // File lists + bool singleUnit; + const char **libraryFiles; + size_t libraryFilesNum; +} MlirImportVerilogOptions; + +/// Parse the specified Verilog inputs into the specified MLIR context. +/// +/// It takes the ownership of buffers. +MLIR_CAPI_EXPORTED MlirLogicalResult mlirImportVerilog( + MlirContext context, MlirModule into, LLVMMemoryBufferRef *buffers, + size_t numBuffers, const MlirImportVerilogOptions *options /* Optional */); + +#ifdef __cplusplus +} +#endif + +#endif // CIRCT_C_IMPORTVERILOG_H diff --git a/lib/CAPI/CMakeLists.txt b/lib/CAPI/CMakeLists.txt index 70753aa3a8fd..358e5de7a4c0 100644 --- a/lib/CAPI/CMakeLists.txt +++ b/lib/CAPI/CMakeLists.txt @@ -5,3 +5,7 @@ add_subdirectory(Dialect) add_subdirectory(Firtool) add_subdirectory(RtgTool) add_subdirectory(Transforms) + +if(CIRCT_SLANG_FRONTEND_ENABLED) + add_subdirectory(ImportVerilog) +endif() diff --git a/lib/CAPI/ImportVerilog/CMakeLists.txt b/lib/CAPI/ImportVerilog/CMakeLists.txt new file mode 100644 index 000000000000..5d95a50bb884 --- /dev/null +++ b/lib/CAPI/ImportVerilog/CMakeLists.txt @@ -0,0 +1,7 @@ +add_circt_public_c_api_library(CIRCTCAPIImportVerilog + ImportVerilog.cpp + + LINK_LIBS PUBLIC + MLIRCAPIIR + CIRCTImportVerilog + ) diff --git a/lib/CAPI/ImportVerilog/ImportVerilog.cpp b/lib/CAPI/ImportVerilog/ImportVerilog.cpp new file mode 100644 index 000000000000..122445846f60 --- /dev/null +++ b/lib/CAPI/ImportVerilog/ImportVerilog.cpp @@ -0,0 +1,102 @@ +//===- ImportVerilog.cpp - C Interface to ImportVerilog -------------------===// +// +// Implements a C Interface for importing Verilog. +// +//===----------------------------------------------------------------------===// + +#include "circt-c/ImportVerilog.h" + +#include "circt/Conversion/ImportVerilog.h" +#include "mlir/CAPI/IR.h" +#include "mlir/CAPI/Support.h" +#include "mlir/Support/Timing.h" +#include "llvm/Support/SourceMgr.h" + +using namespace circt; +using namespace mlir; + +namespace { +std::optional +convertOptions(const MlirImportVerilogOptions *c) { + if (c == nullptr) { + return std::nullopt; + } + + ImportVerilogOptions ret; + + switch (c->mode) { + case MLIR_IMPORT_VERILOG_MODE_ONLY_LINT: + ret.mode = ImportVerilogOptions::Mode::OnlyLint; + break; + case MLIR_IMPORT_VERILOG_MODE_ONLY_PARSE: + ret.mode = ImportVerilogOptions::Mode::OnlyParse; + break; + case MLIR_IMPORT_VERILOG_MODE_FULL: + ret.mode = ImportVerilogOptions::Mode::Full; + break; + default: + llvm_unreachable("unknown mode for importing verilog"); + } + ret.debugInfo = c->debugInfo; + ret.lowerAlwaysAtStarAsComb = c->lowerAlwaysAtStarAsComb; + + const auto toStrs = [](const char **strs, size_t num) { + std::vector vec; + vec.reserve(num); + for (size_t i = 0; i < num; ++i) { + vec.emplace_back(strs[i]); + } + return vec; + }; + + ret.includeDirs = toStrs(c->includeDirs, c->includeDirsNum); + ret.includeSystemDirs = toStrs(c->includeSystemDirs, c->includeSystemDirsNum); + ret.libDirs = toStrs(c->libDirs, c->libDirsNum); + ret.libExts = toStrs(c->libExts, c->libExtsNum); + ret.excludeExts = toStrs(c->excludeExts, c->excludeExtsNum); + ret.ignoreDirectives = toStrs(c->ignoreDirectives, c->ignoreDirectivesNum); + + ret.maxIncludeDepth = + c->maxIncludeDepth == std::numeric_limits::max() + ? std::nullopt + : std::optional{c->maxIncludeDepth}; + ret.defines = toStrs(c->defines, c->definesNum); + ret.undefines = toStrs(c->undefines, c->undefinesNum); + ret.librariesInheritMacros = c->librariesInheritMacros; + + ret.timeScale = + c->timeScale == nullptr ? std::nullopt : std::optional{c->timeScale}; + ret.allowUseBeforeDeclare = c->allowUseBeforeDeclare; + ret.ignoreUnknownModules = c->ignoreUnknownModules; + ret.topModules = toStrs(c->topModules, c->topModulesNum); + ret.paramOverrides = toStrs(c->paramOverrides, c->paramOverridesNum); + + ret.errorLimit = c->errorLimit == std::numeric_limits::max() + ? std::nullopt + : std::optional{c->errorLimit}; + ret.warningOptions = toStrs(c->warningOptions, c->warningOptionsNum); + ret.suppressWarningsPaths = + toStrs(c->suppressWarningsPaths, c->suppressWarningsPathsNum); + + ret.singleUnit = c->singleUnit; + ret.libraryFiles = toStrs(c->libraryFiles, c->libraryFilesNum); + return ret; +} +} // namespace + +MlirLogicalResult mlirImportVerilog(MlirContext context, MlirModule into, + LLVMMemoryBufferRef *buffers, + size_t numBuffers, + const MlirImportVerilogOptions *options) { + auto ctx = unwrap(context); + TimingScope ts; + llvm::SourceMgr sourceMgr; + for (size_t i = 0; i < numBuffers; i++) { + auto buffer = std::unique_ptr{llvm::unwrap(buffers[i])}; + sourceMgr.AddNewSourceBuffer(std::move(buffer), llvm::SMLoc{}); + } + auto opts = convertOptions(options); + return wrap( + importVerilog(sourceMgr, ctx, ts, unwrap(into), + opts.has_value() ? std::addressof(*opts) : nullptr)); +} diff --git a/test/CAPI/CMakeLists.txt b/test/CAPI/CMakeLists.txt index 3610dd9f86e7..aae0f0082297 100644 --- a/test/CAPI/CMakeLists.txt +++ b/test/CAPI/CMakeLists.txt @@ -110,3 +110,18 @@ target_link_libraries(circt-capi-rtgtest-test MLIRCAPIIR CIRCTCAPIRTGTest ) + +add_llvm_executable(circt-capi-sv-test + PARTIAL_SOURCES_INTENDED + sv.c +) +llvm_update_compile_flags(circt-capi-sv-test) + +target_link_libraries(circt-capi-sv-test + PRIVATE + + LLVMCore + MLIRCAPIIR + CIRCTCAPISV + CIRCTCAPIImportVerilog +) diff --git a/test/CAPI/sv.c b/test/CAPI/sv.c new file mode 100644 index 000000000000..45a8cc6f4b19 --- /dev/null +++ b/test/CAPI/sv.c @@ -0,0 +1,62 @@ +//===- sv.c - SystemVerilog Dialect CAPI unit tests -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// RUN: circt-capi-sv-test 2>&1 | FileCheck %s + +#include "circt-c/Dialect/SV.h" +#include "circt-c/ImportVerilog.h" +#include "llvm-c/Core.h" + +#include +#include + +int testImport(MlirContext ctx) { + const char testSv[] = " \ + module ExportTestSimpleModule( \ + input [31:0] in_1, \ + in_2, \ + output [31:0] out \ + ); \ + assign out = in_1 & in_2; \ + endmodule"; + LLVMMemoryBufferRef buf = LLVMCreateMemoryBufferWithMemoryRange( + testSv, strlen(testSv), "/tmp/testModule.sv", false); + MlirModule module = mlirModuleCreateEmpty(mlirLocationUnknownGet(ctx)); + + MlirLogicalResult result = mlirImportVerilog(ctx, module, &buf, 1, NULL); + if (!mlirLogicalResultIsSuccess(result)) { + return 1; + } + + // clang-format off + // CHECK: module { + // CHECK-NEXT: moore.module @ExportTestSimpleModule(in %in_1 : !moore.l32, in %in_2 : !moore.l32, out out : !moore.l32) { + // CHECK-NEXT: %in_1_0 = moore.net name "in_1" wire : + // CHECK-NEXT: %in_2_1 = moore.net name "in_2" wire : + // CHECK-NEXT: %out = moore.net wire : + // CHECK-NEXT: %0 = moore.read %in_1_0 : + // CHECK-NEXT: %1 = moore.read %in_2_1 : + // CHECK-NEXT: %2 = moore.and %0, %1 : l32 + // CHECK-NEXT: moore.assign %out, %2 : l32 + // CHECK-NEXT: moore.assign %in_1_0, %in_1 : l32 + // CHECK-NEXT: moore.assign %in_2_1, %in_2 : l32 + // CHECK-NEXT: %3 = moore.read %out : + // CHECK-NEXT: moore.output %3 : !moore.l32 + // CHECK-NEXT: } + // CHECK-NEXT: } + // clang-format on + mlirOperationDump(mlirModuleGetOperation(module)); + + return 0; +} + +int main(int argc, char **argv) { + MlirContext ctx = mlirContextCreate(); + mlirDialectHandleLoadDialect(mlirGetDialectHandle__sv__(), ctx); + return testImport(ctx); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4349c5c0aa78..2c2d1d27e326 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,7 @@ set(CIRCT_TEST_DEPENDS circt-capi-rtg-pipelines-test circt-capi-rtg-test circt-capi-rtgtest-test + circt-capi-sv-test circt-as circt-bmc circt-dis diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 9f439f5f4b03..ff880d550e37 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -61,7 +61,7 @@ 'arcilator', 'circt-as', 'circt-capi-ir-test', 'circt-capi-om-test', 'circt-capi-firrtl-test', 'circt-capi-firtool-test', 'circt-capi-rtg-pipelines-test', 'circt-capi-rtg-test', - 'circt-capi-rtgtest-test', 'circt-dis', 'circt-lec', 'circt-reduce', + 'circt-capi-rtgtest-test', 'circt-capi-sv-test', 'circt-dis', 'circt-lec', 'circt-reduce', 'circt-synth', 'circt-test', 'circt-translate', 'firtool', 'hlstool', 'om-linker', 'kanagawatool' ]