start implement openfpga shell and use vpr as a macro
This commit is contained in:
parent
e983966a08
commit
523f9ac391
|
@ -165,6 +165,7 @@ add_subdirectory(abc)
|
|||
add_subdirectory(ace2)
|
||||
add_subdirectory(vpr7_x2p)
|
||||
add_subdirectory(vpr)
|
||||
add_subdirectory(openfpga)
|
||||
|
||||
# run make to extract compiler options, linker options and list of source files
|
||||
#add_custom_target(
|
||||
|
@ -243,3 +244,9 @@ set_target_properties(libvpr8 vpr8
|
|||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/vpr"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/vpr"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/vpr")
|
||||
|
||||
set_target_properties(libopenfpga openfpga
|
||||
PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/openfpga"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/openfpga"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/openfpga")
|
||||
|
|
|
@ -100,7 +100,7 @@ class Shell {
|
|||
void set_command_execute_function(const ShellCommandId& cmd_id,
|
||||
std::function<void()> exec_func);
|
||||
void set_command_execute_function(const ShellCommandId& cmd_id,
|
||||
std::function<void(int, char**)> exec_func);
|
||||
std::function<int(int, const char**)> exec_func);
|
||||
void set_command_dependency(const ShellCommandId& cmd_id,
|
||||
const std::vector<ShellCommandId> cmd_dependency);
|
||||
ShellCommandClassId add_command_class(const char* name);
|
||||
|
@ -159,7 +159,7 @@ class Shell {
|
|||
vtr::vector<ShellCommandId, std::function<void(T&, const Command&, const CommandContext&)>> command_standard_execute_functions_;
|
||||
vtr::vector<ShellCommandId, std::function<void(T&)>> command_short_execute_functions_;
|
||||
vtr::vector<ShellCommandId, std::function<void()>> command_builtin_execute_functions_;
|
||||
vtr::vector<ShellCommandId, std::function<void(int, char**)>> command_macro_execute_functions_;
|
||||
vtr::vector<ShellCommandId, std::function<int(int, const char**)>> command_macro_execute_functions_;
|
||||
|
||||
/* Type of execute functions for each command.
|
||||
* This is supposed to be an internal data ONLY
|
||||
|
|
|
@ -176,7 +176,7 @@ void Shell<T>::set_command_execute_function(const ShellCommandId& cmd_id,
|
|||
|
||||
template<class T>
|
||||
void Shell<T>::set_command_execute_function(const ShellCommandId& cmd_id,
|
||||
std::function<void(int, char**)> exec_func) {
|
||||
std::function<int(int, const char**)> exec_func) {
|
||||
VTR_ASSERT(true == valid_command_id(cmd_id));
|
||||
command_execute_function_types_[cmd_id] = MACRO;
|
||||
command_macro_execute_functions_[cmd_id] = exec_func;
|
||||
|
@ -358,7 +358,7 @@ void Shell<T>::execute_command(const char* cmd_line,
|
|||
strcpy(argv[itok], tokens[itok].c_str());
|
||||
}
|
||||
/* Execute the marco function */
|
||||
command_macro_execute_functions_[cmd_id](tokens.size(), argv);
|
||||
command_macro_execute_functions_[cmd_id](tokens.size(), (const char**)argv);
|
||||
/* Free the argv */
|
||||
for (size_t itok = 0; itok < tokens.size(); ++itok) {
|
||||
free(argv[itok]);
|
||||
|
|
|
@ -28,12 +28,14 @@ void shell_execute_print(ShellContext& context) {
|
|||
}
|
||||
|
||||
static
|
||||
void shell_execute_print_macro(int argc, char** argv) {
|
||||
int shell_execute_print_macro(int argc, const char** argv) {
|
||||
VTR_LOG("Number of arguments: %d\n", argc);
|
||||
VTR_LOG("Detailed arguments:\n");
|
||||
for (int iarg = 0; iarg < argc; ++iarg) {
|
||||
VTR_LOG("\t[%d]: %s\n", iarg, argv[iarg]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
cmake_minimum_required(VERSION 3.9)
|
||||
|
||||
project("libopenfpga")
|
||||
|
||||
file(GLOB_RECURSE EXEC_SOURCE src/main.cpp)
|
||||
file(GLOB_RECURSE LIB_SOURCES src/*/*.cpp)
|
||||
file(GLOB_RECURSE LIB_HEADERS src/*/*.h)
|
||||
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
|
||||
|
||||
#Remove test executable from library
|
||||
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCE})
|
||||
|
||||
#Create the library
|
||||
add_library(libopenfpga STATIC
|
||||
${LIB_HEADERS}
|
||||
${LIB_SOURCES})
|
||||
target_include_directories(libopenfpga PUBLIC ${LIB_INCLUDE_DIRS})
|
||||
set_target_properties(libopenfpga PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
|
||||
|
||||
#Specify link-time dependancies
|
||||
target_link_libraries(libopenfpga
|
||||
libarchopenfpga
|
||||
libopenfpgashell
|
||||
libopenfpgautil
|
||||
libvtrutil
|
||||
libvpr8)
|
||||
|
||||
#Create the test executable
|
||||
add_executable(openfpga ${EXEC_SOURCE})
|
||||
target_link_libraries(openfpga libopenfpga)
|
||||
|
||||
#Supress IPO link warnings if IPO is enabled
|
||||
get_target_property(OPENFPGA_USES_IPO openfpga INTERPROCEDURAL_OPTIMIZATION)
|
||||
if (OPENFPGS_USES_IPO)
|
||||
set_target_properties(openfpga PROPERTIES LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS})
|
||||
endif()
|
||||
|
||||
install(TARGETS libopenfpga openfpga DESTINATION bin)
|
|
@ -0,0 +1,155 @@
|
|||
/********************************************************************
|
||||
* Build the OpenFPGA shell interface
|
||||
*******************************************************************/
|
||||
#include "vtr_log.h"
|
||||
#include "command_parser.h"
|
||||
#include "command_echo.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include "vpr_main.h"
|
||||
|
||||
using namespace openfpga;
|
||||
|
||||
class ShellContext {
|
||||
public:
|
||||
int a;
|
||||
};
|
||||
|
||||
static
|
||||
void shell_execute_set(ShellContext& context,
|
||||
const Command& cmd, const CommandContext& cmd_context) {
|
||||
CommandOptionId opt_id = cmd.option("value");
|
||||
/* Get the value of a in the command context */
|
||||
context.a = std::atoi(cmd_context.option_value(cmd, opt_id).c_str());
|
||||
}
|
||||
|
||||
static
|
||||
void shell_execute_print(ShellContext& context) {
|
||||
VTR_LOG("a=%d\n", context.a);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
/* Create the command to launch shell in different modes */
|
||||
Command start_cmd("OpenFPGA");
|
||||
/* Add two options:
|
||||
* '--interactive', -i': launch the interactive mode
|
||||
* '--file', -f': launch the script mode
|
||||
*/
|
||||
CommandOptionId opt_interactive = start_cmd.add_option("interactive", false, "Launch OpenFPGA in interactive mode");
|
||||
start_cmd.set_option_short_name(opt_interactive, "i");
|
||||
|
||||
CommandOptionId opt_script_mode = start_cmd.add_option("file", false, "Launch OpenFPGA in script mode");
|
||||
start_cmd.set_option_require_value(opt_script_mode, OPT_STRING);
|
||||
start_cmd.set_option_short_name(opt_script_mode, "f");
|
||||
|
||||
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. help
|
||||
* 2. exit
|
||||
*/
|
||||
Shell<ShellContext> shell("OpenFPGA");
|
||||
std::string shell_title;
|
||||
|
||||
shell_title += std::string("Author: Xifan Tang\n");
|
||||
shell_title += std::string("The MIT License\n");
|
||||
shell_title += std::string("\n");
|
||||
shell_title += std::string("Copyright (c) 2018 LNIS - The University of Utah\n");
|
||||
shell_title += std::string("\n");
|
||||
shell_title += std::string("Permission is hereby granted, free of charge, to any person obtaining a copy\n");
|
||||
shell_title += std::string("of this software and associated documentation files (the \"Software\"), to deal\n");
|
||||
shell_title += std::string("in the Software without restriction, including without limitation the rights\n");
|
||||
shell_title += std::string("to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n");
|
||||
shell_title += std::string("copies of the Software, and to permit persons to whom the Software is\n");
|
||||
shell_title += std::string("furnished to do so, subject to the following conditions:\n");
|
||||
shell_title += std::string("\n");
|
||||
shell_title += std::string("The above copyright notice and this permission notice shall be included in\n");
|
||||
shell_title += std::string("all copies or substantial portions of the Software.\n");
|
||||
shell_title += std::string("\n");
|
||||
shell_title += std::string("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n");
|
||||
shell_title += std::string("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n");
|
||||
shell_title += std::string("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n");
|
||||
shell_title += std::string("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n");
|
||||
shell_title += std::string("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n");
|
||||
shell_title += std::string("OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n");
|
||||
shell_title += std::string("THE SOFTWARE.\n");
|
||||
|
||||
shell.add_title(shell_title.c_str());
|
||||
|
||||
/* Add a new class of commands */
|
||||
ShellCommandClassId arith_cmd_class = shell.add_command_class("Arithmetic");
|
||||
|
||||
/* Create a command of 'set' with a required option 'value' with a value
|
||||
* This function sets a value to an internal variable of ShellContext
|
||||
*/
|
||||
Command shell_cmd_set("set");
|
||||
CommandOptionId set_opt_value = shell_cmd_set.add_option("value", true, "value of variable");
|
||||
shell_cmd_set.set_option_require_value(set_opt_value, OPT_STRING);
|
||||
ShellCommandId shell_cmd_set_id = shell.add_command(shell_cmd_set, "Set a value to internal variable 'a'");
|
||||
shell.set_command_class(shell_cmd_set_id, arith_cmd_class);
|
||||
shell.set_command_execute_function(shell_cmd_set_id, shell_execute_set);
|
||||
|
||||
/* Create a command of 'print'
|
||||
* This function will print the value of an internal variable of ShellContext
|
||||
*/
|
||||
Command shell_cmd_print("print");
|
||||
ShellCommandId shell_cmd_print_id = shell.add_command(shell_cmd_print, "Print the value of internal variable 'a'");
|
||||
shell.set_command_class(shell_cmd_print_id, arith_cmd_class);
|
||||
shell.set_command_execute_function(shell_cmd_print_id, shell_execute_print);
|
||||
|
||||
/* Create a macro command of 'vpr' which will call the main engine of vpr
|
||||
*/
|
||||
Command shell_cmd_vpr("vpr");
|
||||
ShellCommandId shell_cmd_vpr_id = shell.add_command(shell_cmd_vpr, "A macro function to print arguments");
|
||||
shell.set_command_class(shell_cmd_vpr_id, arith_cmd_class);
|
||||
shell.set_command_execute_function(shell_cmd_vpr_id, vpr::vpr);
|
||||
|
||||
|
||||
/* Add a new class of commands */
|
||||
ShellCommandClassId basic_cmd_class = shell.add_command_class("Basic");
|
||||
|
||||
Command shell_cmd_exit("exit");
|
||||
ShellCommandId shell_cmd_exit_id = shell.add_command(shell_cmd_exit, "Exit the shell");
|
||||
shell.set_command_class(shell_cmd_exit_id, basic_cmd_class);
|
||||
shell.set_command_execute_function(shell_cmd_exit_id, [shell](){shell.exit();});
|
||||
|
||||
/* Note: help must be the last to add because the linking to execute function will do a snapshot on the shell */
|
||||
Command shell_cmd_help("help");
|
||||
ShellCommandId shell_cmd_help_id = shell.add_command(shell_cmd_help, "Launch help desk");
|
||||
shell.set_command_class(shell_cmd_help_id, basic_cmd_class);
|
||||
shell.set_command_execute_function(shell_cmd_help_id, [shell](){shell.print_commands();});
|
||||
|
||||
/* Create the data base for the shell */
|
||||
ShellContext shell_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]));
|
||||
}
|
||||
|
||||
CommandContext start_cmd_context(start_cmd);
|
||||
if (false == parse_command(cmd_opts, start_cmd, start_cmd_context)) {
|
||||
/* Parse fail: Echo the command */
|
||||
print_command_options(start_cmd);
|
||||
} else {
|
||||
/* Parse succeed. Start a shell */
|
||||
if (true == start_cmd_context.option_enable(start_cmd, opt_interactive)) {
|
||||
shell.run_interactive_mode(shell_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(),
|
||||
shell_context);
|
||||
return 0;
|
||||
}
|
||||
/* Reach here there is something wrong, show the help desk */
|
||||
print_command_options(start_cmd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* This is a wrapper file for VPR API. Mirrored from the main.cpp of vpr
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include "vtr_error.h"
|
||||
#include "vtr_memory.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
#include "tatum/error.hpp"
|
||||
|
||||
#include "vpr_exit_codes.h"
|
||||
#include "vpr_error.h"
|
||||
#include "vpr_api.h"
|
||||
#include "vpr_signal_handler.h"
|
||||
#include "vpr_tatum_error.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
namespace vpr {
|
||||
|
||||
/**
|
||||
* VPR program
|
||||
* Generate FPGA architecture given architecture description
|
||||
* Pack, place, and route circuit into FPGA architecture
|
||||
* Electrical timing analysis on results
|
||||
*
|
||||
* Overall steps
|
||||
* 1. Initialization
|
||||
* 2. Pack
|
||||
* 3. Place-and-route and timing analysis
|
||||
* 4. Clean up
|
||||
*/
|
||||
int vpr(int argc, const char** argv) {
|
||||
vtr::ScopedFinishTimer t("The entire flow of VPR");
|
||||
|
||||
t_options Options = t_options();
|
||||
t_arch Arch = t_arch();
|
||||
t_vpr_setup vpr_setup = t_vpr_setup();
|
||||
|
||||
try {
|
||||
vpr_install_signal_handler();
|
||||
|
||||
/* Read options, architecture, and circuit netlist */
|
||||
vpr_init(argc, argv, &Options, &vpr_setup, &Arch);
|
||||
|
||||
if (Options.show_version) {
|
||||
return SUCCESS_EXIT_CODE;
|
||||
}
|
||||
|
||||
bool flow_succeeded = vpr_flow(vpr_setup, Arch);
|
||||
if (!flow_succeeded) {
|
||||
VTR_LOG("VPR failed to implement circuit\n");
|
||||
return UNIMPLEMENTABLE_EXIT_CODE;
|
||||
}
|
||||
|
||||
auto& timing_ctx = g_vpr_ctx.timing();
|
||||
VTR_LOG("Timing analysis took %g seconds (%g STA, %g slack) (%zu full updates: %zu setup, %zu hold, %zu combined).\n",
|
||||
timing_ctx.stats.timing_analysis_wallclock_time(),
|
||||
timing_ctx.stats.sta_wallclock_time,
|
||||
timing_ctx.stats.slack_wallclock_time,
|
||||
timing_ctx.stats.num_full_updates(),
|
||||
timing_ctx.stats.num_full_setup_updates,
|
||||
timing_ctx.stats.num_full_hold_updates,
|
||||
timing_ctx.stats.num_full_setup_hold_updates);
|
||||
|
||||
/* free data structures */
|
||||
vpr_free_all(Arch, vpr_setup);
|
||||
|
||||
VTR_LOG("VPR suceeded\n");
|
||||
|
||||
} catch (const tatum::Error& tatum_error) {
|
||||
VTR_LOG_ERROR("%s\n", format_tatum_error(tatum_error).c_str());
|
||||
|
||||
return ERROR_EXIT_CODE;
|
||||
|
||||
} catch (const VprError& vpr_error) {
|
||||
vpr_print_error(vpr_error);
|
||||
|
||||
if (vpr_error.type() == VPR_ERROR_INTERRUPTED) {
|
||||
return INTERRUPTED_EXIT_CODE;
|
||||
} else {
|
||||
return ERROR_EXIT_CODE;
|
||||
}
|
||||
|
||||
} catch (const vtr::VtrError& vtr_error) {
|
||||
VTR_LOG_ERROR("%s:%d %s\n", vtr_error.filename_c_str(), vtr_error.line(), vtr_error.what());
|
||||
|
||||
return ERROR_EXIT_CODE;
|
||||
}
|
||||
|
||||
/* Signal success to scripts */
|
||||
return SUCCESS_EXIT_CODE;
|
||||
}
|
||||
|
||||
} /* End namespace vpr */
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef VPR_MAIN_H
|
||||
#define VPR_MAIN_H
|
||||
|
||||
/* Begin namespace vpr */
|
||||
namespace vpr {
|
||||
|
||||
int vpr(int argc, const char** argv);
|
||||
|
||||
} /* End namespace vpr */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue