OpenFPGA/libs/libfabrickey/test/fabric_key_assistant.cpp

234 lines
9.4 KiB
C++

/********************************************************************
* Unit test functions to validate the correctness of
* 1. parser of data structures
* 2. writer of data structures
*******************************************************************/
/* Headers from vtrutils */
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from fabric key */
#include "check_fabric_key.h"
#include "command_echo.h"
#include "command_exit_codes.h"
#include "command_parser.h"
#include "read_xml_fabric_key.h"
#include "write_xml_fabric_key.h"
/** @brief Initialize the options from command-line inputs and organize in the
* format that is ready for parsing */
static std::vector<std::string> format_argv(const std::string& cmd_name,
int argc, const char** argv) {
std::vector<std::string> cmd_opts;
cmd_opts.push_back(cmd_name);
for (int iarg = 1; iarg < argc; ++iarg) {
cmd_opts.push_back(std::string(argv[iarg]));
}
return cmd_opts;
}
/** @brief Checks to be done:
* - Each alias of reference key can be found in the input key
*/
static int check_input_and_ref_key_alias_match(
const openfpga::FabricKey& input_key, const openfpga::FabricKey& ref_key,
const bool& verbose) {
size_t num_errors = 0;
size_t num_keys_checked = 0;
float progress = 0.;
VTR_LOG(
"Checking key alias matching between reference key and input keys...\n");
for (openfpga::FabricKeyId key_id : ref_key.keys()) {
/* Note that this is slow. May consider to build a map first */
std::string curr_alias = ref_key.key_alias(key_id);
std::vector<openfpga::FabricKeyId> input_found_keys =
input_key.find_key_by_alias(curr_alias);
progress = static_cast<float>(num_keys_checked) /
static_cast<float>(ref_key.num_keys()) * 100.0;
VTR_LOGV(verbose, "[%lu%] Checking key alias '%s'\r", size_t(progress),
curr_alias.c_str());
if (input_found_keys.empty()) {
VTR_LOG_ERROR(
"Invalid alias '%s' in the reference key (id='%lu'), which does not "
"exist in the input key!\n",
curr_alias.c_str(), size_t(key_id));
num_errors++;
}
if (input_found_keys.size() > 1) {
VTR_LOG_ERROR(
"Invalid alias '%s' in the input key (id='%lu'), which have been "
"found %lu times!\n",
curr_alias.c_str(), size_t(key_id), input_found_keys.size());
num_errors++;
}
num_keys_checked++;
}
VTR_LOG(
"Checking key alias matching between reference key and input keys... %s\n",
num_errors ? "[Fail]" : "[Pass]");
return num_errors ? openfpga::CMD_EXEC_FATAL_ERROR
: openfpga::CMD_EXEC_SUCCESS;
}
/** @brief Checks to be done:
* - Number of configuration regions match
* - Number of keys match
*/
static int check_input_key(const openfpga::FabricKey& input_key,
const openfpga::FabricKey& ref_key,
const bool& verbose) {
if (ref_key.num_regions() != input_key.num_regions()) {
VTR_LOG_ERROR(
"Different number of configuration regions between reference key "
"(='%lu') and input key ('=%lu')!\n",
ref_key.num_regions(), input_key.num_regions());
return openfpga::CMD_EXEC_FATAL_ERROR;
}
if (ref_key.num_keys() != input_key.num_keys()) {
VTR_LOG_ERROR(
"Different number of keys between reference key (='%lu') and input key "
"('=%lu')!\n",
ref_key.num_keys(), input_key.num_keys());
return openfpga::CMD_EXEC_FATAL_ERROR;
}
size_t num_errors = 0;
size_t curr_num_err = 0;
VTR_LOG("Checking key alias in reference key...\n");
curr_num_err = openfpga::check_fabric_key_alias(ref_key, verbose);
VTR_LOG("Checking key alias in reference key... %s\n",
curr_num_err ? "[Fail]" : "[Pass]");
VTR_LOG("Checking key names and values in reference key...\n");
curr_num_err = openfpga::check_fabric_key_names_and_values(ref_key, verbose);
num_errors += curr_num_err;
VTR_LOG("Checking key names and valus in reference key... %s\n",
curr_num_err ? "[Fail]" : "[Pass]");
VTR_LOG("Checking key alias in input key...\n");
curr_num_err = openfpga::check_fabric_key_alias(input_key, verbose);
num_errors += curr_num_err;
VTR_LOG("Checking key alias in input key... %s\n",
curr_num_err ? "[Fail]" : "[Pass]");
num_errors +=
check_input_and_ref_key_alias_match(input_key, ref_key, verbose);
return num_errors ? openfpga::CMD_EXEC_FATAL_ERROR
: openfpga::CMD_EXEC_SUCCESS;
}
/** @brief Checks to be done:
* - Each alias of input key can be found in the reference key
* - Update input key with pair of name and value which matches the alias from
* the reference key
*/
static int update_input_key(openfpga::FabricKey& input_key,
const openfpga::FabricKey& ref_key,
const bool& verbose) {
size_t num_errors = 0;
size_t num_keys_checked = 0;
float progress = 0.;
VTR_LOG("Pairing key alias between reference key and input keys...\n");
for (openfpga::FabricKeyId key_id : input_key.keys()) {
/* Note that this is slow. May consider to build a map first */
std::string curr_alias = input_key.key_alias(key_id);
std::vector<openfpga::FabricKeyId> ref_found_keys =
ref_key.find_key_by_alias(curr_alias);
progress = static_cast<float>(num_keys_checked) /
static_cast<float>(input_key.num_keys()) * 100.0;
VTR_LOGV(verbose, "[%lu%] Pairing key alias '%s'\r", size_t(progress),
curr_alias.c_str());
if (ref_found_keys.empty()) {
VTR_LOG_ERROR(
"Invalid alias '%s' in the input key (id='%lu'), which does not "
"exist in the reference key!\n",
curr_alias.c_str(), size_t(key_id));
num_errors++;
}
if (ref_found_keys.size() > 1) {
VTR_LOG_ERROR(
"Invalid alias '%s' in the reference key (id='%lu'), which have been "
"found %lu times!\n",
curr_alias.c_str(), size_t(key_id));
num_errors++;
}
/* Now we have a key, get the name and value, and update input key */
input_key.set_key_name(key_id, ref_key.key_name(ref_found_keys[0]));
input_key.set_key_value(key_id, ref_key.key_value(ref_found_keys[0]));
VTR_LOGV(verbose, "[%lu%] Pairing key alias '%s' -> ('%s', %lu)\r",
size_t(progress), curr_alias.c_str(),
input_key.key_name(key_id).c_str(), input_key.key_value(key_id));
num_keys_checked++;
}
return num_errors ? openfpga::CMD_EXEC_FATAL_ERROR
: openfpga::CMD_EXEC_SUCCESS;
}
/** @brief Checks to be done:
* - Number of configuration regions match
* - Number of keys match
* - Each alias can be found in the reference key
*/
static int check_and_update_input_key(openfpga::FabricKey& input_key,
const openfpga::FabricKey& ref_key,
const bool& verbose) {
int status = openfpga::CMD_EXEC_SUCCESS;
status = check_input_key(input_key, ref_key, verbose);
if (status != openfpga::CMD_EXEC_SUCCESS) {
return openfpga::CMD_EXEC_FATAL_ERROR;
}
return update_input_key(input_key, ref_key, verbose);
}
int main(int argc, const char** argv) {
/* Create a new command and Initialize the options available in the user
* interface */
openfpga::Command cmd("fabric_key_assistant");
openfpga::CommandOptionId opt_ref =
cmd.add_option("reference", true, "Specify the reference fabric key file");
cmd.set_option_require_value(opt_ref, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_input =
cmd.add_option("input", true, "Specify the hand-crafted fabric key file");
cmd.set_option_require_value(opt_input, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_output = cmd.add_option(
"output", true, "Specify the final fabric key file to be outputted");
cmd.set_option_require_value(opt_output, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_verbose =
cmd.add_option("verbose", false, "Show verbose outputs");
openfpga::CommandOptionId opt_help =
cmd.add_option("help", false, "Show help desk");
/* Parse the option, to avoid issues, we use the command name to replace the
* argv[0] */
std::vector<std::string> cmd_opts = format_argv(cmd.name(), argc, argv);
openfpga::CommandContext cmd_ctx(cmd);
if (false == parse_command(cmd_opts, cmd, cmd_ctx) ||
cmd_ctx.option_enable(cmd, opt_help)) {
/* Echo the command */
print_command_options(cmd);
return openfpga::CMD_EXEC_FATAL_ERROR;
} else {
/* Let user to confirm selected options */
print_command_context(cmd, cmd_ctx);
}
/* Parse the fabric key from an XML file */
VTR_LOG("Read the reference fabric key from an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_ref).c_str());
openfpga::FabricKey ref_key =
openfpga::read_xml_fabric_key(cmd_ctx.option_value(cmd, opt_ref).c_str());
VTR_LOG("Read the hand-crafted fabric key from an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_input).c_str());
openfpga::FabricKey input_key =
openfpga::read_xml_fabric_key(cmd_ctx.option_value(cmd, opt_input).c_str());
/* Check the input key */
if (check_and_update_input_key(input_key, ref_key,
cmd_ctx.option_enable(cmd, opt_verbose))) {
return openfpga::CMD_EXEC_FATAL_ERROR;
}
VTR_LOG("Write the final fabric key to an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_output).c_str());
return openfpga::write_xml_fabric_key(
cmd_ctx.option_value(cmd, opt_output).c_str(), input_key);
}