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:
tangxifan 2022-12-02 16:29:45 -08:00 committed by GitHub
commit 358c3e51ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 427 additions and 136 deletions

View File

@ -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

View File

@ -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

1
.gitignore vendored
View File

@ -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

View File

@ -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}"

159
cmake/modules/SwigLib.cmake Normal file
View File

@ -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()

View File

@ -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
*/ */

View File

@ -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);

View File

@ -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");

View File

@ -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})

View File

@ -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;
}

View File

@ -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

View File

@ -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;
} }

View File

@ -0,0 +1,8 @@
/* SWIG interface file for OpenFPGA shell APIs */
%module openfpga_shell
%{
#include "openfpga_shell.h"
%}
%include "openfpga_shell.h"

View File

@ -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 -

View File

@ -0,0 +1,2 @@
pkg_mkIndex . openfpga_shell.so
exit

View File

@ -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