Merge pull request #1373 from lnis-uofu/xt_module_name_assistant

New utility tool: module name assistant
This commit is contained in:
tangxifan 2023-09-23 18:17:54 -07:00 committed by GitHub
commit 80c93dd6eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 411 additions and 15 deletions

View File

@ -8,7 +8,7 @@ Note that crafting a fabric key is not an easy task for engineers, as its comple
This tool is developed to assist engineers when finalizing fabric key files.
It can apply sanity checks on hand-crafted fabric key files, helping engineers to correct and debug.
The tool can be found at ``/build/libs/libfabrickey/test/fabric_key_assistant``
The tool can be found at ``/build/libs/libfabrickey/fabric_key_assistant``
The tool includes the following options:

View File

@ -11,3 +11,5 @@ OpenFPGA contains a number of utility tools to help users to craft files.
:maxdepth: 2
fabric_key_assistant
module_rename_assistant

View File

@ -0,0 +1,58 @@
.. _utility_module_rename_assistant:
Module Rename Assistant
-----------------------
Module Rename Assistant is a tool to help users to craft module name files (see details in :ref:`file_formats_module_naming_files`).
This tool is useful to adapt module naming from a fabric to another, considering the two fabrics share the same building blocks, i.e., tile, routing blocks *etc.*
For example, when engineers craft a module naming file for a fabric ``A``, and would like to migrate the module naming rules for anthor fabric ``B``, module naming rules have to be adapted due to the changes on default names of building blocks.
The tool can be found at ``/build/libs/libnamemanager/module_rename_assistant``
The tool includes the following options:
.. option:: --reference_fabricA_names <string>
Specifiy a reference module name file for fabric A. This is typically generated by OpenFPGA through the commmand :ref:`openfpga_setup_commands_write_module_naming_rules`. The reference fabric key file is treated as the baseline, on which the renamed module file will be compared to.
.. option:: --renamed_fabricA_names <string>
Specify the hand-crafted module name file for fabric A, which is typically hand-crafted by users.
.. option:: --reference_fabricB_names <string>
Specifiy a reference module name file for fabric B. This is typically generated by OpenFPGA through the commmand :ref:`openfpga_setup_commands_write_module_naming_rules`. The reference fabric key file is treated as the baseline, on which the renamed module file will be compared to.
.. option:: --output <string>
Specify the renamed module name file for fabric B to be outputted. For example, the fabric A contains reference names:
.. code-block:: xml
<module_name default="tile_1__1_" given="tile_4_"/>
while the renamed module for fabric A includes:
.. code-block:: xml
<module_name default="tile_1__1_" given="tile_big"/>
the fabric B shares the same given name ``tile_4_`` but in a different default name.
.. code-block:: xml
<module_name default="tile_2__2_" given="tile_4_"/>
the resulting output renamed module file includes:
.. code-block:: xml
<module_name default="tile_2__2_" given="tile_big"/>
.. option:: --verbose
To enable verbose output
.. option:: --help
Show help desk

View File

@ -32,6 +32,21 @@ bool ModuleNameMap::name_exist(const std::string& tag) const {
return result != tag2names_.end();
}
std::string ModuleNameMap::tag(const std::string& name) const {
auto result = name2tags_.find(name);
if (result == name2tags_.end()) {
VTR_LOG_ERROR("The given customized name '%s' does not exist!\n",
name.c_str());
return std::string();
}
return result->second;
}
bool ModuleNameMap::tag_exist(const std::string& name) const {
auto result = name2tags_.find(name);
return result != name2tags_.end();
}
std::vector<std::string> ModuleNameMap::tags() const {
std::vector<std::string> keys;
for (auto const& element : tag2names_) {

View File

@ -22,6 +22,12 @@ class ModuleNameMap {
/** @brief Check if a name does exist with a given tag. Return true if there
* is a tag-to-name mapping */
bool name_exist(const std::string& tag) const;
/** @brief Check if a tag does exist with a given name. Return true if there
* is a name-to-tag mapping */
bool tag_exist(const std::string& name) const;
/** @brief Get tag with a given name */
std::string tag(const std::string& name) const;
/** @brief return a list of all the current keys */
std::vector<std::string> tags() const;

View File

@ -74,7 +74,7 @@ static int write_xml_module_name_binding(std::fstream& fp,
return 1;
}
write_xml_attribute(fp, XML_MODULE_NAME_ATTRIBUTE_GIVEN, given_name.c_str());
fp << ">"
fp << "/>"
<< "\n";
return 0;

View File

@ -0,0 +1,159 @@
/********************************************************************
* 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 readarchopenfpga */
#include "command_echo.h"
#include "command_exit_codes.h"
#include "command_parser.h"
#include "read_xml_module_name_map.h"
#include "write_xml_module_name_map.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 Convert module renaming rules from fabric A (ref -> renamed) to
* fabric B (given the ref only) Here is an example Fabric A reference names:
* <module_name default="tile_1__1_" given="tile_4_"/>
* Fabric A renamed:
* <module_name default="tile_1__1_" given="tile_big"/>
* Fabric B reference names:
* <module_name default="tile_2__2_" given="tile_4_"/>
* We want a renamed version for fabric B is
* <module_name default="tile_2__2_" given="tile_big"/>
*/
int rename_module_names_for_fabricB_from_fabricA(
const openfpga::ModuleNameMap& refA_module_names,
const openfpga::ModuleNameMap& renamedA_module_names,
const openfpga::ModuleNameMap& refB_module_names,
openfpga::ModuleNameMap& renamedB_module_names, const bool& verbose) {
/* Ensure a clear start */
renamedB_module_names.clear();
for (std::string ref_tag : refA_module_names.tags()) {
std::string ref_given = refA_module_names.name(ref_tag);
if (!renamedA_module_names.name_exist(ref_tag)) {
VTR_LOG_ERROR(
"Fail to find given name for default '%s' in the hand-crafted module "
"names of fabric A!\n",
ref_tag.c_str());
return openfpga::CMD_EXEC_FATAL_ERROR;
}
std::string renamed_given = renamedA_module_names.name(ref_tag);
/* Now find the same given name in refB */
if (!refB_module_names.tag_exist(ref_given)) {
VTR_LOG_ERROR(
"Fail to find default name for the given name '%s' in the reference "
"module names of fabric B!\n",
ref_given.c_str());
return openfpga::CMD_EXEC_FATAL_ERROR;
}
std::string refB_tag = refB_module_names.tag(ref_given);
/* Add the new pair to the renamed modules for fabric B */
renamedB_module_names.set_tag_to_name_pair(refB_tag, renamed_given);
VTR_LOGV(verbose,
"Successfully pair default name '%s' to given '%s' for fabric B\n",
refB_tag.c_str(), renamed_given.c_str());
}
return openfpga::CMD_EXEC_FATAL_ERROR;
}
int main(int argc, const char** argv) {
/* Create a new command and Initialize the options available in the user
* interface */
openfpga::Command cmd("module_rename_assistant");
openfpga::CommandOptionId opt_refA =
cmd.add_option("reference_fabricA_names", true,
"Specify the reference module name file for fabric A");
cmd.set_option_require_value(opt_refA, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_renamedA =
cmd.add_option("renamed_fabricA_names", true,
"Specify the hand-crafted module name file for fabric A");
cmd.set_option_require_value(opt_renamedA, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_refB =
cmd.add_option("reference_fabricB_names", true,
"Specify the reference module name file for fabric B");
cmd.set_option_require_value(opt_refB, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_renamedB = cmd.add_option(
"output", true,
"Specify the renamed module name file for fabric B to be outputted");
cmd.set_option_require_value(opt_renamedB, openfpga::OPT_STRING);
openfpga::CommandOptionId opt_no_time_stamp = cmd.add_option(
"no_time_stamp", false, "Include time stamps in output file");
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);
}
int status = 0;
VTR_LOG(
"Read the reference module names for fabric A from an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_refA).c_str());
openfpga::ModuleNameMap refA_module_names;
status = openfpga::read_xml_module_name_map(
cmd_ctx.option_value(cmd, opt_refA).c_str(), refA_module_names);
if (status != openfpga::CMD_EXEC_SUCCESS) {
return status;
}
VTR_LOG(
"Read the reference module names for fabric B from an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_refB).c_str());
openfpga::ModuleNameMap refB_module_names;
status = openfpga::read_xml_module_name_map(
cmd_ctx.option_value(cmd, opt_refB).c_str(), refB_module_names);
if (status != openfpga::CMD_EXEC_SUCCESS) {
return status;
}
VTR_LOG("Read the renamed module names for fabric A from an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_renamedA).c_str());
openfpga::ModuleNameMap renamedA_module_names;
status = openfpga::read_xml_module_name_map(
cmd_ctx.option_value(cmd, opt_renamedA).c_str(), renamedA_module_names);
if (status != openfpga::CMD_EXEC_SUCCESS) {
return status;
}
/* Now apply name mapping from fabric A to fabric B */
openfpga::ModuleNameMap renamedB_module_names;
status = rename_module_names_for_fabricB_from_fabricA(
refA_module_names, renamedA_module_names, refB_module_names,
renamedB_module_names, cmd_ctx.option_enable(cmd, opt_verbose));
VTR_LOG("Write the renamed module names for fabric B to an XML file: %s.\n",
cmd_ctx.option_value(cmd, opt_renamedB).c_str());
return openfpga::write_xml_module_name_map(
cmd_ctx.option_value(cmd, opt_renamedB).c_str(), renamedB_module_names,
!cmd_ctx.option_enable(cmd, opt_no_time_stamp),
cmd_ctx.option_enable(cmd, opt_verbose));
}

View File

@ -361,16 +361,25 @@ int rename_modules_template(T& openfpga_ctx, const Command& cmd,
std::string file_name = cmd_context.option_value(cmd, opt_file);
if (CMD_EXEC_SUCCESS !=
read_xml_module_name_map(file_name.c_str(),
openfpga_ctx.mutable_module_name_map())) {
int status = CMD_EXEC_SUCCESS;
ModuleNameMap user_module_name_map;
status = read_xml_module_name_map(file_name.c_str(), user_module_name_map);
if (status != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
/* Write hierarchy to a file */
return rename_fabric_modules(openfpga_ctx.mutable_module_graph(),
openfpga_ctx.module_name_map(),
cmd_context.option_enable(cmd, opt_verbose));
/* Apply renaming on the user version */
status = partial_rename_fabric_modules(
openfpga_ctx.mutable_module_graph(), user_module_name_map,
cmd_context.option_enable(cmd, opt_verbose));
if (status != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
/* Update the internal version of module name map based on users' version */
return update_module_name_map_with_user_version(
openfpga_ctx.mutable_module_name_map(), user_module_name_map,
cmd_context.option_enable(cmd, opt_verbose));
}
/********************************************************************

View File

@ -92,18 +92,26 @@ int update_module_map_name_with_indexing_names(ModuleNameMap& module_name_map,
return CMD_EXEC_SUCCESS;
}
/** @brief Apply module renaming for all the modules. Require the module name
* map cover all the modules */
int rename_fabric_modules(ModuleManager& module_manager,
const ModuleNameMap& module_name_map,
const bool& verbose) {
int status = CMD_EXEC_SUCCESS;
size_t cnt = 0;
for (ModuleId curr_module : module_manager.modules()) {
std::string new_name =
module_name_map.name(module_manager.module_name(curr_module));
if (new_name != module_manager.module_name(curr_module)) {
std::string curr_module_name = module_manager.module_name(curr_module);
/* Error out if the new name does not exist ! */
if (!module_name_map.name_exist(curr_module_name)) {
VTR_LOG_ERROR(
"The built-in module name '%s' does not exist! Abort renaming...\n",
curr_module_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
std::string new_name = module_name_map.name(curr_module_name);
if (new_name != curr_module_name) {
VTR_LOGV(verbose, "Rename module '%s' to its new name '%s'\n",
module_manager.module_name(curr_module).c_str(),
new_name.c_str());
curr_module_name.c_str(), new_name.c_str());
module_manager.set_module_name(curr_module, new_name);
}
cnt++;
@ -112,4 +120,70 @@ int rename_fabric_modules(ModuleManager& module_manager,
return status;
}
/** @brief Apply module renaming based on the pairs given by module name map
* only. So not all the modules are renamed. So the module name map just cover a
* subset of modules */
int partial_rename_fabric_modules(ModuleManager& module_manager,
const ModuleNameMap& module_name_map,
const bool& verbose) {
int status = CMD_EXEC_SUCCESS;
size_t cnt = 0;
for (std::string built_in_name : module_name_map.tags()) {
ModuleId curr_module = module_manager.find_module(built_in_name);
if (!module_manager.valid_module_id(curr_module)) {
VTR_LOG_ERROR(
"The built-in module name '%s' does not exist! Abort renaming...\n",
built_in_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
std::string new_name = module_name_map.name(built_in_name);
if (new_name != built_in_name) {
VTR_LOGV(verbose, "Rename module '%s' to its new name '%s'\n",
built_in_name.c_str(), new_name.c_str());
module_manager.set_module_name(curr_module, new_name);
}
cnt++;
}
VTR_LOG("Renamed %lu modules\n", cnt);
return status;
}
/** @brief The module name map kept in openfpga context always has a built-in
* name with coordinates. while users apply renaming or other internal renaming
* is applied, e.g., through option '--name_module_using_index', the module name
* in the module graph can be changed. So in the user's version, the built-in
* name may become index or anything else. We have to keep the built-in name
* consistent (use coordinates, otherwise other engines may not work, which rely
* on this convention) while the given name should follow the users' definition.
* So we need an update here For example: the current module name map is
* 'tile_1__1_' -> 'tile_4_' the user's module name map is 'tile_4_' ->
* 'tile_big' The resulting module name map is 'tile_1__1_' -> 'tile_big'
*/
int update_module_name_map_with_user_version(
ModuleNameMap& curr_module_name_map,
const ModuleNameMap& user_module_name_map, const bool& verbose) {
int status = CMD_EXEC_SUCCESS;
size_t cnt = 0;
for (std::string user_tag : user_module_name_map.tags()) {
if (!curr_module_name_map.tag_exist(user_tag)) {
VTR_LOG_ERROR(
"The built-in module name '%s' given by user does not exist in current "
"module name map! Abort updating...\n",
user_tag.c_str());
return CMD_EXEC_FATAL_ERROR;
}
std::string built_in_tag = curr_module_name_map.tag(user_tag);
curr_module_name_map.set_tag_to_name_pair(
built_in_tag, user_module_name_map.name(user_tag));
VTR_LOGV(verbose,
"Now module built-in name '%s' is pointed to its new name '%s' "
"(old name '%s' is deleted)\n",
built_in_tag.c_str(), user_module_name_map.name(user_tag).c_str(),
user_tag.c_str());
cnt++;
}
VTR_LOGV(verbose, "Update %lu built-in-to-name pairs\n", cnt);
return status;
}
} /* end namespace openfpga */

View File

@ -29,6 +29,14 @@ int rename_fabric_modules(ModuleManager& module_manager,
const ModuleNameMap& module_name_map,
const bool& verbose);
int partial_rename_fabric_modules(ModuleManager& module_manager,
const ModuleNameMap& module_name_map,
const bool& verbose);
int update_module_name_map_with_user_version(
ModuleNameMap& curr_module_name_map,
const ModuleNameMap& user_module_name_map, const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -206,6 +206,7 @@ echo -e "Module naming";
run-task basic_tests/module_naming/using_index $@
run-task basic_tests/module_naming/renaming_rules $@
run-task basic_tests/module_naming/renaming_rules_strong $@
run-task basic_tests/module_naming/renaming_rules_on_indexed_names $@
echo -e "Testing global port definition from tiles";
run-task basic_tests/global_tile_ports/global_tile_clock $@

View File

@ -0,0 +1,12 @@
<module_names>
<module_name default="mux_tree_tapbuf_size10_mem" given="mux_tree_mem_max"/>
<module_name default="mux_tree_size2" given="mux_tree_mini"/>
<module_name default="logical_tile_clb_mode_clb_" given="logical_tile_clb_mode_clb_unique"/>
<module_name default="sb_4_" given="sb_max"/>
<module_name default="cby_1_" given="cby_max"/>
<module_name default="cbx_1_" given="cbx_max"/>
<module_name default="tile_4_" given="tile_clb"/>
<module_name default="tile_7_" given="tile_dsp"/>
<module_name default="fpga_core" given="pfabric_core"/>
<module_name default="fpga_top" given="pfabric_top"/>
</module_names>

View File

@ -0,0 +1,51 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = false
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/module_rename_preconfig_testbench_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_dsp8_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
openfpga_vpr_extra_options=--constant_net_method route --skip_sync_clustering_and_routing_results on
openfpga_pb_pin_fixup_command = pb_pin_fixup --verbose
openfpga_vpr_device=3x2
openfpga_vpr_route_chan_width=60
openfpga_group_tile_config_option=--group_tile ${PATH:TASK_DIR}/config/tile_config.xml
openfpga_verilog_testbench_options=
openfpga_add_fpga_core_module=add_fpga_core_to_fabric --instance_name fpga_core_inst
openfpga_fabric_module_name_options=--name_module_using_index
openfpga_rename_module_file = ${PATH:TASK_DIR}/config/module_names.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_dsp8_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_8/mac_8.v
[SYNTHESIS_PARAM]
# Yosys script parameters
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k4_frac_N8_tileable_reset_softadder_register_scan_chain_dsp8_nonLR_caravel_io_skywater130nm_cell_sim.v
bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k4_frac_N8_tileable_reset_softadder_register_scan_chain_dsp8_nonLR_caravel_io_skywater130nm_dsp_map.v
bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=8 -D DSP_B_MAXWIDTH=8 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_8x8
bench_read_verilog_options_common = -nolatches
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dsp_flow.ys
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
bench0_top = mac_8
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -1,6 +1,6 @@
<module_names>
<module_name default="mux_tree_tapbuf_size10_mem" given="mux_tree_mem_max"/>
<module_name default="mux_tree_size_2" given="mux_tree_mini"/>
<module_name default="mux_tree_size2" given="mux_tree_mini"/>
<module_name default="logical_tile_clb_mode_clb_" given="logical_tile_clb_mode_clb_unique"/>
<module_name default="sb_1__1_" given="sb_max"/>
<module_name default="cby_1__1_" given="cby_max"/>