Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions include/circt-c/ImportVerilog.h
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions lib/CAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
7 changes: 7 additions & 0 deletions lib/CAPI/ImportVerilog/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_circt_public_c_api_library(CIRCTCAPIImportVerilog
ImportVerilog.cpp

LINK_LIBS PUBLIC
MLIRCAPIIR
CIRCTImportVerilog
)
102 changes: 102 additions & 0 deletions lib/CAPI/ImportVerilog/ImportVerilog.cpp
Original file line number Diff line number Diff line change
@@ -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<ImportVerilogOptions>
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<std::string> 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<uint32_t>::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<uint32_t>::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::MemoryBuffer>{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));
}
15 changes: 15 additions & 0 deletions test/CAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
62 changes: 62 additions & 0 deletions test/CAPI/sv.c
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
#include <string.h>

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 : <l32>
// CHECK-NEXT: %in_2_1 = moore.net name "in_2" wire : <l32>
// CHECK-NEXT: %out = moore.net wire : <l32>
// CHECK-NEXT: %0 = moore.read %in_1_0 : <l32>
// CHECK-NEXT: %1 = moore.read %in_2_1 : <l32>
// 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 : <l32>
// 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);
}
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
]
Expand Down
Loading