Merge pull request #921 from lnis-uofu/xt_swig
SWIG APIs for Tcl/Python binding with initial practice on Tcl interface
This commit is contained in:
commit
358c3e51ca
|
@ -149,6 +149,7 @@ jobs:
|
||||||
build/vtr-verilog-to-routing/vpr/libvpr.a
|
build/vtr-verilog-to-routing/vpr/libvpr.a
|
||||||
build/vtr-verilog-to-routing/vpr/vpr
|
build/vtr-verilog-to-routing/vpr/vpr
|
||||||
build/openfpga/libopenfpga.a
|
build/openfpga/libopenfpga.a
|
||||||
|
build/openfpga/openfpga_shell.so
|
||||||
build/openfpga/openfpga
|
build/openfpga/openfpga
|
||||||
yosys/install/share
|
yosys/install/share
|
||||||
yosys/install/bin
|
yosys/install/bin
|
||||||
|
@ -184,6 +185,10 @@ jobs:
|
||||||
cc: gcc-9
|
cc: gcc-9
|
||||||
cxx: g++-9
|
cxx: g++-9
|
||||||
cmake_flags: "-DOPENFPGA_WITH_VERSION=OFF"
|
cmake_flags: "-DOPENFPGA_WITH_VERSION=OFF"
|
||||||
|
- name: "Build w/o SWIG support (Ubuntu 20.04)"
|
||||||
|
cc: gcc-9
|
||||||
|
cxx: g++-9
|
||||||
|
cmake_flags: "-DOPENFPGA_WITH_SWIG=OFF"
|
||||||
# Define the steps to run the build job
|
# Define the steps to run the build job
|
||||||
env:
|
env:
|
||||||
CC: ${{ matrix.config.cc }}
|
CC: ${{ matrix.config.cc }}
|
||||||
|
@ -271,6 +276,7 @@ jobs:
|
||||||
- name: quicklogic_reg_test
|
- name: quicklogic_reg_test
|
||||||
- name: vtr_benchmark_reg_test
|
- name: vtr_benchmark_reg_test
|
||||||
- name: iwls_benchmark_reg_test
|
- name: iwls_benchmark_reg_test
|
||||||
|
- name: tcl_reg_test
|
||||||
steps:
|
steps:
|
||||||
- name: Cancel previous
|
- name: Cancel previous
|
||||||
uses: styfle/cancel-workflow-action@0.9.1
|
uses: styfle/cancel-workflow-action@0.9.1
|
||||||
|
@ -328,6 +334,7 @@ jobs:
|
||||||
- name: quicklogic_reg_test
|
- name: quicklogic_reg_test
|
||||||
- name: vtr_benchmark_reg_test
|
- name: vtr_benchmark_reg_test
|
||||||
- name: iwls_benchmark_reg_test
|
- name: iwls_benchmark_reg_test
|
||||||
|
- name: tcl_reg_test
|
||||||
steps:
|
steps:
|
||||||
- name: Cancel previous
|
- name: Cancel previous
|
||||||
uses: styfle/cancel-workflow-action@0.9.1
|
uses: styfle/cancel-workflow-action@0.9.1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
apt-get install --no-install-recommends -y \
|
apt-get install --no-install-recommends -y \
|
||||||
libdatetime-perl libc6 libffi-dev libgcc1 libreadline8 libstdc++6 \
|
libdatetime-perl libc6 libffi-dev libgcc1 libreadline8 libstdc++6 \
|
||||||
libtcl8.6 python3.8 python3-pip zlib1g libbz2-1.0 \
|
libtcl8.6 tcl python3.8 python3-pip zlib1g libbz2-1.0 \
|
||||||
iverilog git rsync make curl wget tree python3.8-venv
|
iverilog git rsync make curl wget tree python3.8-venv
|
||||||
|
|
|
@ -28,6 +28,7 @@ __pycache__/
|
||||||
*.d
|
*.d
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
|
*.so
|
||||||
vpr7_x2p/vpr/vpr
|
vpr7_x2p/vpr/vpr
|
||||||
vpr7_x2p/printhandler/printhandlerdemo
|
vpr7_x2p/printhandler/printhandlerdemo
|
||||||
vpr7_x2p/libarchfpga/read_arch
|
vpr7_x2p/libarchfpga/read_arch
|
||||||
|
|
|
@ -55,6 +55,7 @@ set(OPENFPGA_VERSION_PRERELEASE "dev")
|
||||||
# Include user-defined functions
|
# Include user-defined functions
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||||
include(FilesToDirs)
|
include(FilesToDirs)
|
||||||
|
include(SwigLib)
|
||||||
|
|
||||||
# Set the assertion level
|
# Set the assertion level
|
||||||
add_definitions("-DVTR_ASSERT_LEVEL=${VTR_ASSERT_LEVEL}")
|
add_definitions("-DVTR_ASSERT_LEVEL=${VTR_ASSERT_LEVEL}")
|
||||||
|
@ -68,6 +69,7 @@ option(OPENFPGA_WITH_YOSYS "Enable building Yosys" ON)
|
||||||
option(OPENFPGA_WITH_YOSYS_PLUGIN "Enable building Yosys plugin" ON)
|
option(OPENFPGA_WITH_YOSYS_PLUGIN "Enable building Yosys plugin" ON)
|
||||||
option(OPENFPGA_WITH_TEST "Enable testing build for codebase. Once enabled, make test can be run" ON)
|
option(OPENFPGA_WITH_TEST "Enable testing build for codebase. Once enabled, make test can be run" ON)
|
||||||
option(OPENFPGA_WITH_VERSION "Enable version always-up-to-date when building codebase. Disable only when you do not care an accurate version number" ON)
|
option(OPENFPGA_WITH_VERSION "Enable version always-up-to-date when building codebase. Disable only when you do not care an accurate version number" ON)
|
||||||
|
option(OPENFPGA_WITH_SWIG "Enable SWIG interface when building codebase. Disable when you do not need high-level interfaces, such as Tcl/Python" ON)
|
||||||
|
|
||||||
# Options pass on to VTR
|
# Options pass on to VTR
|
||||||
set(WITH_ABC ON CACHE BOOL "Enable building ABC in Verilog-to-Routing")
|
set(WITH_ABC ON CACHE BOOL "Enable building ABC in Verilog-to-Routing")
|
||||||
|
@ -82,6 +84,21 @@ set(ODIN_YOSYS OFF CACHE BOOL "Enable building odin with yosys in Verilog-to-Rou
|
||||||
set(YOSYS_SV_UHDM_PLUGIN OFF CACHE BOOL "Enable building and installing Yosys SystemVerilog and UHDM plugins in Verilog-to-Routing")
|
set(YOSYS_SV_UHDM_PLUGIN OFF CACHE BOOL "Enable building and installing Yosys SystemVerilog and UHDM plugins in Verilog-to-Routing")
|
||||||
set(VTR_ENABLE_VERSION ${OPENFPGA_WITH_VERSION} CACHE BOOL "Enable version always-up-to-date when building codebase. Disable only when you do not care an accurate version number")
|
set(VTR_ENABLE_VERSION ${OPENFPGA_WITH_VERSION} CACHE BOOL "Enable version always-up-to-date when building codebase. Disable only when you do not care an accurate version number")
|
||||||
|
|
||||||
|
# TCL file/lib required to link with SWIG generated wrapper
|
||||||
|
if (OPENFPGA_WITH_SWIG)
|
||||||
|
#Find Tcl
|
||||||
|
include(FindTCL)
|
||||||
|
message(STATUS "tcl.h path is : ${TCL_INCLUDE_PATH}")
|
||||||
|
message(STATUS "libtcl.so path is : ${TCL_LIBRARY}")
|
||||||
|
|
||||||
|
#Find SWIG
|
||||||
|
find_package(SWIG 3.0 REQUIRED)
|
||||||
|
if (SWIG_VERSION VERSION_GREATER_EQUAL "4.1.0")
|
||||||
|
message(WARNING "Using SWIG >= ${SWIG_VERSION} -flatstaticmethod flag for python")
|
||||||
|
endif()
|
||||||
|
include(UseSWIG)
|
||||||
|
endif()
|
||||||
|
|
||||||
#Compiler flag configuration checks
|
#Compiler flag configuration checks
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
|
@ -219,10 +236,17 @@ if(OPENFPGA_ENABLE_SANITIZE)
|
||||||
link_libraries("-static-libasan") #Fixes 'ASan runtime does not come first in initial library list'
|
link_libraries("-static-libasan") #Fixes 'ASan runtime does not come first in initial library list'
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Extra flags
|
||||||
|
set(SWIG_SHARED_FLAGS "")
|
||||||
|
if (OPENFPGA_WITH_SWIG)
|
||||||
|
set(SWIG_SHARED_FLAGS "-fpic")
|
||||||
|
endif()
|
||||||
|
add_compile_options(${SWIG_SHARED_FLAGS})
|
||||||
|
|
||||||
# Set final flags
|
# Set final flags
|
||||||
#
|
#
|
||||||
separate_arguments(
|
separate_arguments(
|
||||||
ADDITIONAL_FLAGS UNIX_COMMAND "${SANITIZE_FLAGS} ${PROFILING_FLAGS} ${COVERAGE_FLAGS} ${LOGGING_FLAGS} ${COLORED_COMPILE} ${EXTRA_FLAGS}"
|
ADDITIONAL_FLAGS UNIX_COMMAND "${SANITIZE_FLAGS} ${PROFILING_FLAGS} ${COVERAGE_FLAGS} ${LOGGING_FLAGS} ${COLORED_COMPILE} ${EXTRA_FLAGS} ${SWIG_SHARED_FLAGS}"
|
||||||
)
|
)
|
||||||
separate_arguments(
|
separate_arguments(
|
||||||
WARN_FLAGS UNIX_COMMAND "${WARN_FLAGS}"
|
WARN_FLAGS UNIX_COMMAND "${WARN_FLAGS}"
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
# This is adapt based on the OpenROAD cmake module:
|
||||||
|
# https://github.com/The-OpenROAD-Project/OpenROAD/tree/master/src/cmake
|
||||||
|
#
|
||||||
|
# Sets up swig for a .i file and encode .tcl files
|
||||||
|
# Arguments
|
||||||
|
# NAME <library>: the generated library name
|
||||||
|
# I_FILE <file>: the .i file input to swig
|
||||||
|
# NAMESPACE <name>: the namespace prefix in TCL
|
||||||
|
# SWIG_INCLUDES <dir>* : optional list of include dirs for swig
|
||||||
|
# SCRIPTS <file>* : tcl files to encode
|
||||||
|
#
|
||||||
|
# The intention is that this will create a library target with the
|
||||||
|
# generated code in it. Additional c++ source will be added to the
|
||||||
|
# target with target_sources() afterwards.
|
||||||
|
|
||||||
|
function(SwigLib)
|
||||||
|
|
||||||
|
# Parse args
|
||||||
|
set(options "")
|
||||||
|
set(oneValueArgs I_FILE NAME NAMESPACE LANGUAGE RUNTIME_HEADER)
|
||||||
|
set(multiValueArgs SWIG_INCLUDES SCRIPTS)
|
||||||
|
|
||||||
|
cmake_parse_arguments(
|
||||||
|
ARG # prefix on the parsed args
|
||||||
|
"${options}"
|
||||||
|
"${oneValueArgs}"
|
||||||
|
"${multiValueArgs}"
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Validate args
|
||||||
|
if (DEFINED ARG_UNPARSED_ARGUMENTS)
|
||||||
|
message(FATAL_ERROR "Unknown argument(s) to SwigLib: ${ARG_UNPARSED_ARGUMENTS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED ARG_KEYWORDS_MISSING_VALUES)
|
||||||
|
message(FATAL_ERROR "Missing value for argument(s) to SwigLib: ${ARG_KEYWORDS_MISSING_VALUES}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(arg I_FILE NAME NAMESPACE)
|
||||||
|
if (NOT DEFINED ARG_${arg})
|
||||||
|
message(FATAL_ERROR "${arg} argument must be provided to SwigLib")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Default to tcl if unspecified
|
||||||
|
if (NOT DEFINED ARG_LANGUAGE)
|
||||||
|
set(ARG_LANGUAGE tcl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_source_files_properties(${ARG_I_FILE} PROPERTIES CPLUSPLUS ON)
|
||||||
|
|
||||||
|
if (DEFINED ARG_SWIG_INCLUDES)
|
||||||
|
set_property(SOURCE ${ARG_I_FILE}
|
||||||
|
PROPERTY INCLUDE_DIRECTORIES ${ARG_SWIG_INCLUDES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${ARG_LANGUAGE} STREQUAL "tcl")
|
||||||
|
set(LANGUAGE_OPTIONS -namespace -prefix ${ARG_NAMESPACE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup swig of I_FILE.
|
||||||
|
set_property(SOURCE ${ARG_I_FILE}
|
||||||
|
PROPERTY COMPILE_OPTIONS ${LANGUAGE_OPTIONS}
|
||||||
|
-Werror
|
||||||
|
-w317,325,378,401,402,467,472,503,509)
|
||||||
|
|
||||||
|
set_property(SOURCE ${ARG_I_FILE}
|
||||||
|
PROPERTY SWIG_MODULE_NAME ${ARG_NAME})
|
||||||
|
set_property(SOURCE ${ARG_I_FILE}
|
||||||
|
PROPERTY USE_SWIG_DEPENDENCIES TRUE)
|
||||||
|
set_property(SOURCE ${ARG_I_FILE}
|
||||||
|
PROPERTY USE_TARGET_INCLUDE_DIRECTORIES true)
|
||||||
|
|
||||||
|
# Use shared library which can be loaded in tclsh runtime
|
||||||
|
swig_add_library(${ARG_NAME}
|
||||||
|
LANGUAGE ${ARG_LANGUAGE}
|
||||||
|
TYPE SHARED
|
||||||
|
SOURCES ${ARG_I_FILE}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Disable problematic compiler warnings on generated files.
|
||||||
|
# At this point only the swig generated sources are present.
|
||||||
|
get_target_property(GEN_SRCS ${ARG_NAME} SOURCES)
|
||||||
|
|
||||||
|
foreach(GEN_SRC ${GEN_SRCS})
|
||||||
|
set_source_files_properties(${GEN_SRC}
|
||||||
|
PROPERTIES
|
||||||
|
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces"
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# These includes are always needed.
|
||||||
|
# FIXME: Should be made as a parameter or set a rule to put all the dependent headers in a directory, i.e., include/
|
||||||
|
target_include_directories(${ARG_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/base
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/mux_lib
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/annotation
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/repack
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/fpga_bitstream
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/fabric
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/tile_direct
|
||||||
|
)
|
||||||
|
|
||||||
|
if (${ARG_LANGUAGE} STREQUAL tcl)
|
||||||
|
target_include_directories(${ARG_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${TCL_INCLUDE_PATH}
|
||||||
|
)
|
||||||
|
elseif (${ARG_LANGUAGE} STREQUAL python)
|
||||||
|
target_include_directories(${ARG_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${Python3_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
if (SWIG_VERSION VERSION_GREATER_EQUAL "4.1.0")
|
||||||
|
set_property(TARGET ${ARG_NAME} PROPERTY SWIG_COMPILE_OPTIONS -flatstaticmethod)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
swig_link_libraries(${ARG_NAME}
|
||||||
|
PUBLIC
|
||||||
|
Python3::Python
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED ARG_RUNTIME_HEADER)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${ARG_RUNTIME_HEADER}
|
||||||
|
COMMAND ${SWIG_EXECUTABLE} -${ARG_LANGUAGE} -external-runtime ${ARG_RUNTIME_HEADER}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
add_custom_target(${ARG_NAME}_RUNTIME_HEADER
|
||||||
|
DEPENDS ${ARG_RUNTIME_HEADER}
|
||||||
|
)
|
||||||
|
add_dependencies(${ARG_NAME}
|
||||||
|
${ARG_NAME}_RUNTIME_HEADER
|
||||||
|
)
|
||||||
|
target_include_directories(${ARG_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Generate the encoded of the script files.
|
||||||
|
if (DEFINED ARG_SCRIPTS)
|
||||||
|
set(LANG_INIT ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}-${ARG_LANGUAGE}InitVar.cc)
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT ${LANG_INIT}
|
||||||
|
COMMAND ${OPENSTA_HOME}/etc/TclEncode.tcl ${LANG_INIT} ${ARG_NAME}_${ARG_LANGUAGE}_inits ${ARG_SCRIPTS}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
DEPENDS ${ARG_SCRIPTS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${ARG_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${LANG_INIT}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
|
@ -75,7 +75,7 @@ class Shell {
|
||||||
};
|
};
|
||||||
|
|
||||||
public: /* Constructor */
|
public: /* Constructor */
|
||||||
Shell<T>(const char* name);
|
Shell<T>();
|
||||||
|
|
||||||
public: /* Public accessors */
|
public: /* Public accessors */
|
||||||
std::string name() const;
|
std::string name() const;
|
||||||
|
@ -96,6 +96,7 @@ class Shell {
|
||||||
const ShellCommandClassId& cmd_class_id) const;
|
const ShellCommandClassId& cmd_class_id) const;
|
||||||
|
|
||||||
public: /* Public mutators */
|
public: /* Public mutators */
|
||||||
|
void set_name(const char* name);
|
||||||
void add_title(const char* title);
|
void add_title(const char* title);
|
||||||
ShellCommandId add_command(const Command& cmd, const char* descr);
|
ShellCommandId add_command(const Command& cmd, const char* descr);
|
||||||
void set_command_class(const ShellCommandId& cmd_id,
|
void set_command_class(const ShellCommandId& cmd_id,
|
||||||
|
@ -177,8 +178,6 @@ class Shell {
|
||||||
int execution_errors() const;
|
int execution_errors() const;
|
||||||
/* Quit the shell */
|
/* Quit the shell */
|
||||||
void exit(const int& init_err = 0) const;
|
void exit(const int& init_err = 0) const;
|
||||||
|
|
||||||
private: /* Private executors */
|
|
||||||
/* Execute a command, the command line is the user's input to launch a command
|
/* Execute a command, the command line is the user's input to launch a command
|
||||||
* The common_context is the data structure to exchange data between commands
|
* The common_context is the data structure to exchange data between commands
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,8 +26,8 @@ namespace openfpga {
|
||||||
* Public constructors
|
* Public constructors
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
template<class T>
|
template<class T>
|
||||||
Shell<T>::Shell(const char* name) {
|
Shell<T>::Shell() {
|
||||||
name_ = std::string(name);
|
name_ = std::string("shell_no_name");
|
||||||
time_start_ = 0;
|
time_start_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,11 @@ std::vector<ShellCommandId> Shell<T>::commands_by_class(const ShellCommandClassI
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Public mutators
|
* Public mutators
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
template<class T>
|
||||||
|
void Shell<T>::set_name(const char* name) {
|
||||||
|
name_ = std::string(name);
|
||||||
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void Shell<T>::add_title(const char* title) {
|
void Shell<T>::add_title(const char* title) {
|
||||||
title_ = std::string(title);
|
title_ = std::string(title);
|
||||||
|
|
|
@ -63,7 +63,8 @@ int main(int argc, char** argv) {
|
||||||
* 1. help
|
* 1. help
|
||||||
* 2. exit
|
* 2. exit
|
||||||
*/
|
*/
|
||||||
Shell<ShellContext> shell("test_shell");
|
Shell<ShellContext> shell;
|
||||||
|
shell.set_name("test_shell");
|
||||||
std::string shell_title;
|
std::string shell_title;
|
||||||
|
|
||||||
shell_title += std::string("The MIT License\n");
|
shell_title += std::string("The MIT License\n");
|
||||||
|
|
|
@ -10,7 +10,19 @@ files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
|
||||||
#Remove test executable from library
|
#Remove test executable from library
|
||||||
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCE})
|
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCE})
|
||||||
|
|
||||||
|
if (OPENFPGA_WITH_SWIG)
|
||||||
|
# SWIG library
|
||||||
|
SwigLib(NAME openfpga_shell
|
||||||
|
NAMESPACE std
|
||||||
|
LANGUAGE tcl
|
||||||
|
I_FILE src/openfpga_shell.i)
|
||||||
|
target_include_directories(openfpga_shell PUBLIC ${LIB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(openfpga_shell
|
||||||
|
libopenfpga)
|
||||||
|
endif()
|
||||||
|
|
||||||
#Create the library
|
#Create the library
|
||||||
|
#Static linked library for other C++ libraries
|
||||||
add_library(libopenfpga STATIC
|
add_library(libopenfpga STATIC
|
||||||
${LIB_HEADERS}
|
${LIB_HEADERS}
|
||||||
${LIB_SOURCES})
|
${LIB_SOURCES})
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include "openfpga_shell.h"
|
||||||
|
|
||||||
|
#include "basic_command.h"
|
||||||
|
#include "command_echo.h"
|
||||||
|
#include "command_parser.h"
|
||||||
|
#include "openfpga_bitstream_command.h"
|
||||||
|
#include "openfpga_context.h"
|
||||||
|
#include "openfpga_sdc_command.h"
|
||||||
|
#include "openfpga_setup_command.h"
|
||||||
|
#include "openfpga_spice_command.h"
|
||||||
|
#include "openfpga_title.h"
|
||||||
|
#include "openfpga_verilog_command.h"
|
||||||
|
#include "vpr_command.h"
|
||||||
|
|
||||||
|
OpenfpgaShell::OpenfpgaShell() {
|
||||||
|
shell_.set_name("OpenFPGA");
|
||||||
|
shell_.add_title(create_openfpga_title().c_str());
|
||||||
|
|
||||||
|
/* Add vpr commands */
|
||||||
|
openfpga::add_vpr_commands(shell_);
|
||||||
|
|
||||||
|
/* Add openfpga setup commands */
|
||||||
|
openfpga::add_openfpga_setup_commands(shell_);
|
||||||
|
|
||||||
|
/* Add openfpga verilog commands */
|
||||||
|
openfpga::add_openfpga_verilog_commands(shell_);
|
||||||
|
|
||||||
|
/* Add openfpga bitstream commands */
|
||||||
|
openfpga::add_openfpga_bitstream_commands(shell_);
|
||||||
|
|
||||||
|
/* Add openfpga SPICE commands */
|
||||||
|
openfpga::add_openfpga_spice_commands(shell_);
|
||||||
|
|
||||||
|
/* Add openfpga sdc commands */
|
||||||
|
openfpga::add_openfpga_sdc_commands(shell_);
|
||||||
|
|
||||||
|
/* Add basic commands: exit, help, etc.
|
||||||
|
* Note:
|
||||||
|
* This MUST be the last command group to be added!
|
||||||
|
*/
|
||||||
|
openfpga::add_basic_commands(shell_);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OpenfpgaShell::run_command(const char* cmd_line) {
|
||||||
|
return shell_.execute_command(cmd_line, openfpga_ctx_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenfpgaShell::reset() {
|
||||||
|
/* TODO: reset the shell status */
|
||||||
|
/* TODO: reset the data storage */
|
||||||
|
}
|
||||||
|
|
||||||
|
int OpenfpgaShell::start(int argc, char** argv) {
|
||||||
|
reset();
|
||||||
|
|
||||||
|
/* Create the command to launch shell in different modes */
|
||||||
|
openfpga::Command start_cmd("OpenFPGA");
|
||||||
|
/* Add options to openfpga shell interface */
|
||||||
|
/* '--interactive', -i': launch the interactive mode */
|
||||||
|
openfpga::CommandOptionId opt_interactive = start_cmd.add_option(
|
||||||
|
"interactive", false, "Launch OpenFPGA in interactive mode");
|
||||||
|
start_cmd.set_option_short_name(opt_interactive, "i");
|
||||||
|
|
||||||
|
/* '--file', -f': launch the script mode */
|
||||||
|
openfpga::CommandOptionId opt_script_mode =
|
||||||
|
start_cmd.add_option("file", false, "Launch OpenFPGA in script mode");
|
||||||
|
start_cmd.set_option_require_value(opt_script_mode, openfpga::OPT_STRING);
|
||||||
|
start_cmd.set_option_short_name(opt_script_mode, "f");
|
||||||
|
|
||||||
|
/* '--batch_execution': execute the script in batch mode.
|
||||||
|
* Will exit immediately when fatal errors occurred
|
||||||
|
*/
|
||||||
|
openfpga::CommandOptionId opt_batch_exec =
|
||||||
|
start_cmd.add_option("batch_execution", false,
|
||||||
|
"Launch OpenFPGA in batch mode when running scripts");
|
||||||
|
start_cmd.set_option_short_name(opt_batch_exec, "batch");
|
||||||
|
|
||||||
|
/* '--version', -v': print version information */
|
||||||
|
openfpga::CommandOptionId opt_version =
|
||||||
|
start_cmd.add_option("version", false, "Show OpenFPGA version");
|
||||||
|
start_cmd.set_option_short_name(opt_version, "v");
|
||||||
|
|
||||||
|
/* '--help', -h': print help desk */
|
||||||
|
openfpga::CommandOptionId opt_help =
|
||||||
|
start_cmd.add_option("help", false, "Help desk");
|
||||||
|
start_cmd.set_option_short_name(opt_help, "h");
|
||||||
|
|
||||||
|
/* Parse the option, to avoid issues, we use the command name to replace the
|
||||||
|
* argv[0] */
|
||||||
|
std::vector<std::string> cmd_opts;
|
||||||
|
cmd_opts.push_back(start_cmd.name());
|
||||||
|
for (int iarg = 1; iarg < argc; ++iarg) {
|
||||||
|
cmd_opts.push_back(std::string(argv[iarg]));
|
||||||
|
}
|
||||||
|
|
||||||
|
openfpga::CommandContext start_cmd_context(start_cmd);
|
||||||
|
if (false == parse_command(cmd_opts, start_cmd, start_cmd_context)) {
|
||||||
|
/* Parse fail: Echo the command */
|
||||||
|
openfpga::print_command_options(start_cmd);
|
||||||
|
} else {
|
||||||
|
/* Parse succeed. Branch on options */
|
||||||
|
/* Show version */
|
||||||
|
if (true == start_cmd_context.option_enable(start_cmd, opt_version)) {
|
||||||
|
print_openfpga_version_info();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Start a shell */
|
||||||
|
if (true == start_cmd_context.option_enable(start_cmd, opt_interactive)) {
|
||||||
|
shell_.run_interactive_mode(openfpga_ctx_);
|
||||||
|
return shell_.exit_code();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true == start_cmd_context.option_enable(start_cmd, opt_script_mode)) {
|
||||||
|
shell_.run_script_mode(
|
||||||
|
start_cmd_context.option_value(start_cmd, opt_script_mode).c_str(),
|
||||||
|
openfpga_ctx_,
|
||||||
|
start_cmd_context.option_enable(start_cmd, opt_batch_exec));
|
||||||
|
return shell_.exit_code();
|
||||||
|
}
|
||||||
|
/* Reach here there is something wrong, show the help desk */
|
||||||
|
openfpga::print_command_options(start_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reach here, it means shell execution has critical errors.
|
||||||
|
* Return a code with fatal errors
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef OPENFPGA_SHELL_H
|
||||||
|
#define OPENFPGA_SHELL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "openfpga_context.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This is a shell class built on top of the general-purpose shell
|
||||||
|
* It is dedicated for the usage of OpenFPGA engines
|
||||||
|
* - It includes the data storage required
|
||||||
|
* - It includes all the commands available in OpenFPGA
|
||||||
|
*******************************************************************/
|
||||||
|
class OpenfpgaShell {
|
||||||
|
public: /* Contructors */
|
||||||
|
OpenfpgaShell();
|
||||||
|
|
||||||
|
public: /* Mutators */
|
||||||
|
/* Execute a specific command with options in a line, which is available in
|
||||||
|
* the shell Note that running a command will be based on the current status
|
||||||
|
* of data storage. The data storage is impacted by previous commands that
|
||||||
|
* have been run. If you want a clear start, please call API reset() before
|
||||||
|
* running a command. Running a command may cause modification to data
|
||||||
|
* storage. */
|
||||||
|
int run_command(const char* cmd_line);
|
||||||
|
|
||||||
|
/* Start the shell with options. For detailed usage, please refer to online
|
||||||
|
* documentation about openfpgashell Depending on the options, a shell may run
|
||||||
|
* in
|
||||||
|
* - an interactive mode, where users can type in commands and get results
|
||||||
|
* or
|
||||||
|
* - an batch mode, where users provide a script contains a set of commands to
|
||||||
|
* execute
|
||||||
|
* TODO: the shell always has a clean start (refreshed data storage).
|
||||||
|
*/
|
||||||
|
int start(int argc, char** argv);
|
||||||
|
|
||||||
|
/* Reset the data storage and shell status, to ensure a clean start */
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private: /* Internal data */
|
||||||
|
openfpga::Shell<OpenfpgaContext> shell_;
|
||||||
|
OpenfpgaContext openfpga_ctx_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,136 +1,12 @@
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Build the OpenFPGA shell interface
|
* Build the OpenFPGA shell interface
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
/* Header file from vtrutil library */
|
#include "openfpga_shell.h"
|
||||||
#include "vtr_log.h"
|
|
||||||
#include "vtr_time.h"
|
|
||||||
|
|
||||||
/* Header file from libopenfpgashell library */
|
|
||||||
#include "command_echo.h"
|
|
||||||
#include "command_parser.h"
|
|
||||||
#include "shell.h"
|
|
||||||
|
|
||||||
/* Header file from openfpga */
|
|
||||||
#include "basic_command.h"
|
|
||||||
#include "openfpga_bitstream_command.h"
|
|
||||||
#include "openfpga_context.h"
|
|
||||||
#include "openfpga_sdc_command.h"
|
|
||||||
#include "openfpga_setup_command.h"
|
|
||||||
#include "openfpga_spice_command.h"
|
|
||||||
#include "openfpga_title.h"
|
|
||||||
#include "openfpga_verilog_command.h"
|
|
||||||
#include "vpr_command.h"
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Main function to start OpenFPGA shell interface
|
* Main function to start OpenFPGA shell interface
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
/* Create the command to launch shell in different modes */
|
OpenfpgaShell openfpga_shell;
|
||||||
openfpga::Command start_cmd("OpenFPGA");
|
return openfpga_shell.start(argc, argv);
|
||||||
/* Add options to openfpga shell interface */
|
|
||||||
/* '--interactive', -i': launch the interactive mode */
|
|
||||||
openfpga::CommandOptionId opt_interactive = start_cmd.add_option(
|
|
||||||
"interactive", false, "Launch OpenFPGA in interactive mode");
|
|
||||||
start_cmd.set_option_short_name(opt_interactive, "i");
|
|
||||||
|
|
||||||
/* '--file', -f': launch the script mode */
|
|
||||||
openfpga::CommandOptionId opt_script_mode =
|
|
||||||
start_cmd.add_option("file", false, "Launch OpenFPGA in script mode");
|
|
||||||
start_cmd.set_option_require_value(opt_script_mode, openfpga::OPT_STRING);
|
|
||||||
start_cmd.set_option_short_name(opt_script_mode, "f");
|
|
||||||
|
|
||||||
/* '--batch_execution': execute the script in batch mode.
|
|
||||||
* Will exit immediately when fatal errors occurred
|
|
||||||
*/
|
|
||||||
openfpga::CommandOptionId opt_batch_exec =
|
|
||||||
start_cmd.add_option("batch_execution", false,
|
|
||||||
"Launch OpenFPGA in batch mode when running scripts");
|
|
||||||
start_cmd.set_option_short_name(opt_batch_exec, "batch");
|
|
||||||
|
|
||||||
/* '--version', -v': print version information */
|
|
||||||
openfpga::CommandOptionId opt_version =
|
|
||||||
start_cmd.add_option("version", false, "Show OpenFPGA version");
|
|
||||||
start_cmd.set_option_short_name(opt_version, "v");
|
|
||||||
|
|
||||||
/* '--help', -h': print help desk */
|
|
||||||
openfpga::CommandOptionId opt_help =
|
|
||||||
start_cmd.add_option("help", false, "Help desk");
|
|
||||||
start_cmd.set_option_short_name(opt_help, "h");
|
|
||||||
|
|
||||||
/* Create a shell object
|
|
||||||
* Add two commands, which are
|
|
||||||
* 1. exit
|
|
||||||
* 2. help. This must the last to add
|
|
||||||
*/
|
|
||||||
openfpga::Shell<OpenfpgaContext> shell("OpenFPGA");
|
|
||||||
|
|
||||||
shell.add_title(create_openfpga_title().c_str());
|
|
||||||
|
|
||||||
/* Add vpr commands */
|
|
||||||
openfpga::add_vpr_commands(shell);
|
|
||||||
|
|
||||||
/* Add openfpga setup commands */
|
|
||||||
openfpga::add_openfpga_setup_commands(shell);
|
|
||||||
|
|
||||||
/* Add openfpga verilog commands */
|
|
||||||
openfpga::add_openfpga_verilog_commands(shell);
|
|
||||||
|
|
||||||
/* Add openfpga bitstream commands */
|
|
||||||
openfpga::add_openfpga_bitstream_commands(shell);
|
|
||||||
|
|
||||||
/* Add openfpga SPICE commands */
|
|
||||||
openfpga::add_openfpga_spice_commands(shell);
|
|
||||||
|
|
||||||
/* Add openfpga sdc commands */
|
|
||||||
openfpga::add_openfpga_sdc_commands(shell);
|
|
||||||
|
|
||||||
/* Add basic commands: exit, help, etc.
|
|
||||||
* Note:
|
|
||||||
* This MUST be the last command group to be added!
|
|
||||||
*/
|
|
||||||
openfpga::add_basic_commands(shell);
|
|
||||||
|
|
||||||
/* Create the data base for the shell */
|
|
||||||
OpenfpgaContext openfpga_context;
|
|
||||||
|
|
||||||
/* Parse the option, to avoid issues, we use the command name to replace the
|
|
||||||
* argv[0] */
|
|
||||||
std::vector<std::string> cmd_opts;
|
|
||||||
cmd_opts.push_back(start_cmd.name());
|
|
||||||
for (int iarg = 1; iarg < argc; ++iarg) {
|
|
||||||
cmd_opts.push_back(std::string(argv[iarg]));
|
|
||||||
}
|
|
||||||
|
|
||||||
openfpga::CommandContext start_cmd_context(start_cmd);
|
|
||||||
if (false == parse_command(cmd_opts, start_cmd, start_cmd_context)) {
|
|
||||||
/* Parse fail: Echo the command */
|
|
||||||
openfpga::print_command_options(start_cmd);
|
|
||||||
} else {
|
|
||||||
/* Parse succeed. Branch on options */
|
|
||||||
/* Show version */
|
|
||||||
if (true == start_cmd_context.option_enable(start_cmd, opt_version)) {
|
|
||||||
print_openfpga_version_info();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Start a shell */
|
|
||||||
if (true == start_cmd_context.option_enable(start_cmd, opt_interactive)) {
|
|
||||||
shell.run_interactive_mode(openfpga_context);
|
|
||||||
return shell.exit_code();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true == start_cmd_context.option_enable(start_cmd, opt_script_mode)) {
|
|
||||||
shell.run_script_mode(
|
|
||||||
start_cmd_context.option_value(start_cmd, opt_script_mode).c_str(),
|
|
||||||
openfpga_context,
|
|
||||||
start_cmd_context.option_enable(start_cmd, opt_batch_exec));
|
|
||||||
return shell.exit_code();
|
|
||||||
}
|
|
||||||
/* Reach here there is something wrong, show the help desk */
|
|
||||||
openfpga::print_command_options(start_cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reach here, it means shell execution has critical errors.
|
|
||||||
* Return a code with fatal errors
|
|
||||||
*/
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
/* SWIG interface file for OpenFPGA shell APIs */
|
||||||
|
%module openfpga_shell
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "openfpga_shell.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%include "openfpga_shell.h"
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
###############################################
|
||||||
|
# OpenFPGA Shell in Tcl
|
||||||
|
##############################################
|
||||||
|
source openfpga.sh
|
||||||
|
echo -e "Regression tests for OpenFPGA in Tcl Shell";
|
||||||
|
|
||||||
|
cd build/openfpga
|
||||||
|
${OPENFPGA_PATH}/openfpga_flow/scripts/swig_tcl_example.tcl
|
||||||
|
cd -
|
|
@ -0,0 +1,2 @@
|
||||||
|
pkg_mkIndex . openfpga_shell.so
|
||||||
|
exit
|
|
@ -0,0 +1,10 @@
|
||||||
|
#! /bin/env tclsh
|
||||||
|
# Load dynamic linked library
|
||||||
|
load "openfpga_shell.so" openfpga_shell
|
||||||
|
# Create a new Openfpga shell
|
||||||
|
std::OpenfpgaShell openfpga_shell
|
||||||
|
# Run an command
|
||||||
|
openfpga_shell run_command "help"
|
||||||
|
# Finish the quit
|
||||||
|
#openfpga_shell run_command "exit"
|
||||||
|
#exit
|
Loading…
Reference in New Issue