Merge pull request #993 from lnis-uofu/ext_exec
New command ``ext_exec`` to allow system call; Automate bus group generation in openfpga shell scripts
This commit is contained in:
commit
dba59b0460
|
@ -20,7 +20,7 @@ source
|
||||||
|
|
||||||
.. option:: --command_stream <string>
|
.. option:: --command_stream <string>
|
||||||
|
|
||||||
A string/file stream which contains the commands to be executed. Use quote(``"``) to split between commands. For example,
|
A string/file stream which contains the commands to be executed. Use quote(``"``) to group command and semicolumn(``;``) to split between commands. For example,
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
|
@ -36,6 +36,19 @@ source
|
||||||
|
|
||||||
.. note:: If you are sourcing a file when running OpenFPGA in script mode, please turn on the batch mode here. See details in :ref:`launch_openfpga_shell`
|
.. note:: If you are sourcing a file when running OpenFPGA in script mode, please turn on the batch mode here. See details in :ref:`launch_openfpga_shell`
|
||||||
|
|
||||||
|
ext_exec
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Run a system call for a command which is not in OpenFPGA shell
|
||||||
|
|
||||||
|
.. option:: --command <string>
|
||||||
|
|
||||||
|
A string stream which contains the command to be executed. Use quote(``"``) to group command. For example,
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
ext_exec --command "ls -all"
|
||||||
|
|
||||||
exit
|
exit
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
@ -7,58 +7,43 @@
|
||||||
#include "basic_command.h"
|
#include "basic_command.h"
|
||||||
|
|
||||||
#include "command_exit_codes.h"
|
#include "command_exit_codes.h"
|
||||||
|
#include "openfpga_basic.h"
|
||||||
#include "openfpga_title.h"
|
#include "openfpga_title.h"
|
||||||
|
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
static int source_existing_command(openfpga::Shell<OpenfpgaContext>* shell,
|
/********************************************************************
|
||||||
OpenfpgaContext& openfpga_ctx,
|
* - Add a command to Shell environment: exec_external
|
||||||
const Command& cmd,
|
* - Add associated options
|
||||||
const CommandContext& cmd_context) {
|
* - Add command dependency
|
||||||
CommandOptionId opt_file = cmd.option("from_file");
|
*******************************************************************/
|
||||||
CommandOptionId opt_batch_mode = cmd.option("batch_mode");
|
static ShellCommandId add_openfpga_ext_exec_command(
|
||||||
CommandOptionId opt_ss = cmd.option("command_stream");
|
openfpga::Shell<OpenfpgaContext>& shell,
|
||||||
|
const ShellCommandClassId& cmd_class_id,
|
||||||
|
const std::vector<ShellCommandId>& dependent_cmds) {
|
||||||
|
Command shell_cmd("ext_exec");
|
||||||
|
|
||||||
bool is_cmd_file = cmd_context.option_enable(cmd, opt_file);
|
/* Add an option '--command_stream' */
|
||||||
std::string cmd_ss = cmd_context.option_value(cmd, opt_ss);
|
CommandOptionId opt_cmdstream = shell_cmd.add_option(
|
||||||
|
"command", true,
|
||||||
|
"A string stream which contains the commands to be executed");
|
||||||
|
shell_cmd.set_option_require_value(opt_cmdstream, openfpga::OPT_STRING);
|
||||||
|
|
||||||
int status = CMD_EXEC_SUCCESS;
|
/* Add command to the Shell */
|
||||||
|
ShellCommandId shell_cmd_id = shell.add_command(
|
||||||
|
shell_cmd, "Source a string of commands or execute a script from a file");
|
||||||
|
shell.set_command_class(shell_cmd_id, cmd_class_id);
|
||||||
|
shell.set_command_execute_function(shell_cmd_id, call_external_command);
|
||||||
|
|
||||||
/* If a file is specified, run script mode of the shell, otherwise, */
|
/* Add command dependency to the Shell */
|
||||||
if (is_cmd_file) {
|
shell.set_command_dependency(shell_cmd_id, dependent_cmds);
|
||||||
shell->run_script_mode(cmd_ss.c_str(), openfpga_ctx,
|
|
||||||
cmd_context.option_enable(cmd, opt_batch_mode));
|
|
||||||
} else {
|
|
||||||
/* Split the string with ';' and run each command */
|
|
||||||
/* Remove the space at the end of the line
|
|
||||||
* So that we can check easily if there is a continued line in the end
|
|
||||||
*/
|
|
||||||
StringToken cmd_ss_tokenizer(cmd_ss);
|
|
||||||
|
|
||||||
for (std::string cmd_part : cmd_ss_tokenizer.split(";")) {
|
return shell_cmd_id;
|
||||||
StringToken cmd_part_tokenizer(cmd_part);
|
|
||||||
cmd_part_tokenizer.rtrim(std::string(" "));
|
|
||||||
std::string single_cmd_line = cmd_part_tokenizer.data();
|
|
||||||
|
|
||||||
if (!single_cmd_line.empty()) {
|
|
||||||
status = shell->execute_command(single_cmd_line.c_str(), openfpga_ctx);
|
|
||||||
|
|
||||||
/* Check the execution status of the command,
|
|
||||||
* if fatal error happened, we should abort immediately
|
|
||||||
*/
|
|
||||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
|
||||||
return CMD_EXEC_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CMD_EXEC_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* - Add a command to Shell environment: repack
|
* - Add a command to Shell environment: source
|
||||||
* - Add associated options
|
* - Add associated options
|
||||||
* - Add command dependency
|
* - Add command dependency
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
@ -83,7 +68,7 @@ static ShellCommandId add_openfpga_source_command(
|
||||||
"batch_mode", false,
|
"batch_mode", false,
|
||||||
"Enable batch mode when executing the script from a file (not a string)");
|
"Enable batch mode when executing the script from a file (not a string)");
|
||||||
|
|
||||||
/* Add command 'repack' to the Shell */
|
/* Add command to the Shell */
|
||||||
ShellCommandId shell_cmd_id = shell.add_command(
|
ShellCommandId shell_cmd_id = shell.add_command(
|
||||||
shell_cmd, "Source a string of commands or execute a script from a file");
|
shell_cmd, "Source a string of commands or execute a script from a file");
|
||||||
shell.set_command_class(shell_cmd_id, cmd_class_id);
|
shell.set_command_class(shell_cmd_id, cmd_class_id);
|
||||||
|
@ -126,6 +111,10 @@ void add_basic_commands(openfpga::Shell<OpenfpgaContext>& shell) {
|
||||||
add_openfpga_source_command(shell, basic_cmd_class,
|
add_openfpga_source_command(shell, basic_cmd_class,
|
||||||
std::vector<ShellCommandId>());
|
std::vector<ShellCommandId>());
|
||||||
|
|
||||||
|
/* Add 'exec_external command which can run system call */
|
||||||
|
add_openfpga_ext_exec_command(shell, basic_cmd_class,
|
||||||
|
std::vector<ShellCommandId>());
|
||||||
|
|
||||||
/* Note:
|
/* Note:
|
||||||
* help MUST be the last to add because the linking to execute function will
|
* help MUST be the last to add because the linking to execute function will
|
||||||
* do a snapshot on the shell
|
* do a snapshot on the shell
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/********************************************************************
|
||||||
|
* Add basic commands to the OpenFPGA shell interface, including:
|
||||||
|
* - exit
|
||||||
|
* - version
|
||||||
|
* - help
|
||||||
|
*******************************************************************/
|
||||||
|
#include "openfpga_basic.h"
|
||||||
|
|
||||||
|
#include "command_exit_codes.h"
|
||||||
|
#include "openfpga_title.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
int source_existing_command(openfpga::Shell<OpenfpgaContext>* shell,
|
||||||
|
OpenfpgaContext& openfpga_ctx, const Command& cmd,
|
||||||
|
const CommandContext& cmd_context) {
|
||||||
|
CommandOptionId opt_file = cmd.option("from_file");
|
||||||
|
CommandOptionId opt_batch_mode = cmd.option("batch_mode");
|
||||||
|
CommandOptionId opt_ss = cmd.option("command_stream");
|
||||||
|
|
||||||
|
bool is_cmd_file = cmd_context.option_enable(cmd, opt_file);
|
||||||
|
std::string cmd_ss = cmd_context.option_value(cmd, opt_ss);
|
||||||
|
|
||||||
|
int status = CMD_EXEC_SUCCESS;
|
||||||
|
|
||||||
|
/* If a file is specified, run script mode of the shell, otherwise, */
|
||||||
|
if (is_cmd_file) {
|
||||||
|
shell->run_script_mode(cmd_ss.c_str(), openfpga_ctx,
|
||||||
|
cmd_context.option_enable(cmd, opt_batch_mode));
|
||||||
|
} else {
|
||||||
|
/* Split the string with ';' and run each command */
|
||||||
|
/* Remove the space at the end of the line
|
||||||
|
* So that we can check easily if there is a continued line in the end
|
||||||
|
*/
|
||||||
|
StringToken cmd_ss_tokenizer(cmd_ss);
|
||||||
|
|
||||||
|
for (std::string cmd_part : cmd_ss_tokenizer.split(";")) {
|
||||||
|
StringToken cmd_part_tokenizer(cmd_part);
|
||||||
|
cmd_part_tokenizer.rtrim(std::string(" "));
|
||||||
|
std::string single_cmd_line = cmd_part_tokenizer.data();
|
||||||
|
|
||||||
|
if (!single_cmd_line.empty()) {
|
||||||
|
status = shell->execute_command(single_cmd_line.c_str(), openfpga_ctx);
|
||||||
|
|
||||||
|
/* Check the execution status of the command,
|
||||||
|
* if fatal error happened, we should abort immediately
|
||||||
|
*/
|
||||||
|
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_EXEC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Call an external command using system call */
|
||||||
|
int call_external_command(const Command& cmd,
|
||||||
|
const CommandContext& cmd_context) {
|
||||||
|
CommandOptionId opt_ss = cmd.option("command");
|
||||||
|
|
||||||
|
std::string cmd_ss = cmd_context.option_value(cmd, opt_ss);
|
||||||
|
|
||||||
|
/* First test if command processor is available and then execute */
|
||||||
|
if (!system(NULL)) {
|
||||||
|
VTR_LOG("Processer is not available");
|
||||||
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return system(cmd_ss.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef OPENFPGA_BASIC_H
|
||||||
|
#define OPENFPGA_BASIC_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
#include "command.h"
|
||||||
|
#include "command_context.h"
|
||||||
|
#include "openfpga_context.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
int source_existing_command(openfpga::Shell<OpenfpgaContext>* shell,
|
||||||
|
OpenfpgaContext& openfpga_ctx, const Command& cmd,
|
||||||
|
const CommandContext& cmd_context);
|
||||||
|
|
||||||
|
int call_external_command(const Command& cmd,
|
||||||
|
const CommandContext& cmd_context);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Run VPR for the 'and' design
|
||||||
|
#--write_rr_graph example_rr_graph.xml
|
||||||
|
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling ideal
|
||||||
|
|
||||||
|
# Read OpenFPGA architecture definition
|
||||||
|
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
|
||||||
|
|
||||||
|
# Read OpenFPGA simulation settings
|
||||||
|
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
|
||||||
|
|
||||||
|
# Annotate the OpenFPGA architecture to VPR data base
|
||||||
|
# to debug use --verbose options
|
||||||
|
link_openfpga_arch --sort_gsb_chan_node_in_edges
|
||||||
|
|
||||||
|
# Check and correct any naming conflicts in the BLIF netlist
|
||||||
|
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
||||||
|
|
||||||
|
# Apply fix-up to Look-Up Table truth tables based on packing results
|
||||||
|
lut_truth_table_fixup
|
||||||
|
|
||||||
|
# Build the module graph
|
||||||
|
# - Enabled compression on routing architecture modules
|
||||||
|
# - Enable pin duplication on grid modules
|
||||||
|
build_fabric --compress_routing #--verbose
|
||||||
|
|
||||||
|
# Write the fabric hierarchy of module graph to a file
|
||||||
|
# This is used by hierarchical PnR flows
|
||||||
|
write_fabric_hierarchy --file ./fabric_hierarchy.txt
|
||||||
|
|
||||||
|
# Repack the netlist to physical pbs
|
||||||
|
# This must be done before bitstream generator and testbench generation
|
||||||
|
# Strongly recommend it is done after all the fix-up have been applied
|
||||||
|
repack #--verbose
|
||||||
|
|
||||||
|
# Build the bitstream
|
||||||
|
# - Output the fabric-independent bitstream to a file
|
||||||
|
build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
|
||||||
|
|
||||||
|
# Build fabric-dependent bitstream
|
||||||
|
build_fabric_bitstream --verbose
|
||||||
|
|
||||||
|
# Write fabric-dependent bitstream
|
||||||
|
write_fabric_bitstream --file fabric_bitstream.bit --format plain_text
|
||||||
|
|
||||||
|
# Write the Verilog netlist for FPGA fabric
|
||||||
|
# - Enable the use of explicit port mapping in Verilog netlist
|
||||||
|
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --verbose
|
||||||
|
|
||||||
|
# Generate a bus group file by calling an external python script
|
||||||
|
ext_exec --command "python3 ../../../../config/bus_group_gen.py --task ../../../../config/counter8_bus_group_task.yaml"
|
||||||
|
|
||||||
|
# Write the Verilog testbench for FPGA fabric
|
||||||
|
# - We suggest the use of same output directory as fabric Verilog netlists
|
||||||
|
# - Must specify the reference benchmark file if you want to output any testbenches
|
||||||
|
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
|
||||||
|
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
|
||||||
|
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
|
||||||
|
write_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC ${OPENFPGA_VERILOG_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} --bus_group_file ${OPENFPGA_BUS_GROUP_FILE}
|
||||||
|
write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} --bus_group_file ${OPENFPGA_BUS_GROUP_FILE}
|
||||||
|
|
||||||
|
# Finish and exit OpenFPGA
|
||||||
|
exit
|
||||||
|
|
||||||
|
# Note :
|
||||||
|
# To run verification at the end of the flow maintain source in ./SRC directory
|
|
@ -190,6 +190,7 @@ run-task basic_tests/bus_group/preconfig_testbench_explicit_mapping $@
|
||||||
run-task basic_tests/bus_group/preconfig_testbench_implicit_mapping $@
|
run-task basic_tests/bus_group/preconfig_testbench_implicit_mapping $@
|
||||||
run-task basic_tests/bus_group/full_testbench_explicit_mapping $@
|
run-task basic_tests/bus_group/full_testbench_explicit_mapping $@
|
||||||
run-task basic_tests/bus_group/full_testbench_implicit_mapping $@
|
run-task basic_tests/bus_group/full_testbench_implicit_mapping $@
|
||||||
|
run-task basic_tests/bus_group/auto_gen_bus_group $@
|
||||||
|
|
||||||
echo -e "Testing fix pins features";
|
echo -e "Testing fix pins features";
|
||||||
run-task basic_tests/io_constraints/fix_pins $@
|
run-task basic_tests/io_constraints/fix_pins $@
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
#####################################################################
|
||||||
|
# A script to create a bus group file based on an input verilog file
|
||||||
|
# The bug group file is an input required by OpenFPGA
|
||||||
|
#####################################################################
|
||||||
|
import os
|
||||||
|
from os.path import dirname, abspath
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import hashlib
|
||||||
|
import yaml
|
||||||
|
import pyverilog
|
||||||
|
from pyverilog.dataflow.dataflow_analyzer import VerilogDataflowAnalyzer
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Error codes
|
||||||
|
#####################################################################
|
||||||
|
error_codes = {
|
||||||
|
"SUCCESS": 0,
|
||||||
|
"MD5_ERROR": 1,
|
||||||
|
"OPTION_ERROR": 2,
|
||||||
|
"FILE_ERROR": 3
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Initialize logger
|
||||||
|
#####################################################################
|
||||||
|
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO);
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Generate the string for a Verilog port
|
||||||
|
#####################################################################
|
||||||
|
def gen_verilog_port_str(port_name, msb, lsb):
|
||||||
|
port_str = str(port_name) + "[" + str(msb) + ":" + str(lsb) + "]"
|
||||||
|
return port_str
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Generate the string for a flatten Verilog port
|
||||||
|
#####################################################################
|
||||||
|
def gen_flatten_verilog_port_str(port_name, pin_id):
|
||||||
|
port_str = str(port_name) + "_" + str(pin_id) + "_"
|
||||||
|
return port_str
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Parse a verilog file and collect bus port information
|
||||||
|
#####################################################################
|
||||||
|
def parse_verilog_file_bus_ports(verilog_files, top_module):
|
||||||
|
# Check if verilog file exists
|
||||||
|
verilog_file_list = []
|
||||||
|
for verilog_f in verilog_files:
|
||||||
|
print(verilog_f)
|
||||||
|
verilog_f_abspath = os.path.abspath(verilog_f["name"])
|
||||||
|
if not os.path.exists(verilog_f_abspath):
|
||||||
|
raise IOError("file not found: " + verilog_f_abspath)
|
||||||
|
|
||||||
|
verilog_file_list.append(verilog_f_abspath)
|
||||||
|
|
||||||
|
# Parse verilog file
|
||||||
|
analyzer = VerilogDataflowAnalyzer(verilog_file_list, top_module)
|
||||||
|
analyzer.generate()
|
||||||
|
# Get port information
|
||||||
|
terms = analyzer.getTerms()
|
||||||
|
# Create XML tree
|
||||||
|
xml = minidom.Document()
|
||||||
|
bus_group = xml.createElement("bus_group")
|
||||||
|
xml.appendChild(bus_group)
|
||||||
|
for tk, tv in sorted(terms.items(), key=lambda x: str(x[0])):
|
||||||
|
logging.debug(tv.name)
|
||||||
|
logging.debug(tv.termtype)
|
||||||
|
logging.debug("[" + str(tv.lsb) + ":" + str(tv.msb) + "]")
|
||||||
|
for tk, tv in sorted(terms.items(), key=lambda x: str(x[0])):
|
||||||
|
# Skip ports that do not belong to top module
|
||||||
|
if (top_module != str(tv.name).split(".")[-2]):
|
||||||
|
continue
|
||||||
|
port_name = str(tv.name).split(".")[-1]
|
||||||
|
|
||||||
|
# Skip minus lsb or msb, which are in don't care set
|
||||||
|
if (("Minus" == str(tv.lsb)) or ("Minus" == str(tv.msb))):
|
||||||
|
continue
|
||||||
|
port_lsb = int(str(tv.lsb))
|
||||||
|
port_msb = int(str(tv.msb))
|
||||||
|
# Only care input and outports
|
||||||
|
if ((not ("Input" in tv.termtype)) and (not ("Output" in tv.termtype))):
|
||||||
|
continue
|
||||||
|
# Only care bus (msb - lsb > 0)
|
||||||
|
if (abs(port_lsb - port_msb) == 0):
|
||||||
|
continue
|
||||||
|
# Reaching here, this is a bus port we need
|
||||||
|
# Get the second part of the name, which is the port name
|
||||||
|
cur_bus = xml.createElement("bus")
|
||||||
|
cur_bus.setAttribute("name", gen_verilog_port_str(port_name, port_msb, port_lsb))
|
||||||
|
# Get if this is little endian or not
|
||||||
|
cur_bus.setAttribute("big_endian", "false")
|
||||||
|
if (port_lsb > port_msb):
|
||||||
|
cur_bus.setAttribute("big_endian", "true")
|
||||||
|
bus_group.appendChild(cur_bus)
|
||||||
|
# Add all the pins
|
||||||
|
for ipin in range(min([port_msb, port_lsb]), max([port_msb, port_lsb]) + 1):
|
||||||
|
cur_pin = xml.createElement("pin")
|
||||||
|
cur_pin.setAttribute('id', str(ipin))
|
||||||
|
cur_pin.setAttribute('name', gen_flatten_verilog_port_str(port_name, ipin))
|
||||||
|
cur_bus.appendChild(cur_pin)
|
||||||
|
|
||||||
|
return xml, bus_group
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Generate bus group files with a given task list
|
||||||
|
#####################################################################
|
||||||
|
def generate_bus_group_files(task_db):
|
||||||
|
# Iterate over all the tasks
|
||||||
|
for verilog_fname in task_db.keys():
|
||||||
|
space_limit = 120
|
||||||
|
log_str = "Parsing verilog file: "
|
||||||
|
top_module_name = task_db[verilog_fname]["top_module"]
|
||||||
|
logging_space = "." * (space_limit - len(log_str) - len(top_module_name))
|
||||||
|
logging.info(log_str + top_module_name)
|
||||||
|
xml, bus_group_data = parse_verilog_file_bus_ports(task_db[verilog_fname]["source"], top_module_name)
|
||||||
|
logging.info(log_str + top_module_name + logging_space + "Done")
|
||||||
|
# Write bus ports to an XML file
|
||||||
|
bus_group_frelname = task_db[verilog_fname]["bus_group_file"]
|
||||||
|
bus_group_fname = os.path.abspath(bus_group_frelname)
|
||||||
|
log_str = "Writing bus group file:"
|
||||||
|
logging_space = "." * (space_limit - len(log_str) - len(bus_group_frelname))
|
||||||
|
logging.info(log_str + bus_group_frelname)
|
||||||
|
xml_str = xml.toprettyxml(indent="\t")
|
||||||
|
with open(bus_group_fname, "w") as bus_group_f:
|
||||||
|
bus_group_f.write(xml_str)
|
||||||
|
logging.info(log_str + bus_group_frelname + logging_space + "Done")
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Read task list from a yaml file
|
||||||
|
#####################################################################
|
||||||
|
def read_yaml_to_task_database(yaml_filename):
|
||||||
|
task_db = {}
|
||||||
|
with open(yaml_filename, 'r') as stream:
|
||||||
|
try:
|
||||||
|
task_db = yaml.load(stream, Loader=yaml.FullLoader)
|
||||||
|
logging.info("Found " + str(len(task_db)) + " tasks to create symbolic links")
|
||||||
|
except yaml.YAMLError as exc:
|
||||||
|
logging.error(exc)
|
||||||
|
exit(error_codes["FILE_ERROR"]);
|
||||||
|
|
||||||
|
return task_db
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Write result database to a yaml file
|
||||||
|
#####################################################################
|
||||||
|
def write_result_database_to_yaml(result_db, yaml_filename):
|
||||||
|
with open(yaml_filename, 'w') as yaml_file:
|
||||||
|
yaml.dump(result_db, yaml_file, default_flow_style=False)
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Main function
|
||||||
|
#####################################################################
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Execute when the module is not initialized from an import statement
|
||||||
|
|
||||||
|
# Parse the options and apply sanity checks
|
||||||
|
parser = argparse.ArgumentParser(description='Create bus group files for Verilog inputs')
|
||||||
|
parser.add_argument('--task_list',
|
||||||
|
required=True,
|
||||||
|
help='Configuration file in YAML format which contains a list of input Verilog and output bus group files')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Create a database for tasks
|
||||||
|
task_db = {}
|
||||||
|
task_db = read_yaml_to_task_database(args.task_list)
|
||||||
|
|
||||||
|
# Generate links based on the task list in database
|
||||||
|
generate_bus_group_files(task_db)
|
||||||
|
logging.info("Created " + str(len(task_db)) + " bus group files")
|
||||||
|
exit(error_codes["SUCCESS"])
|
|
@ -0,0 +1,5 @@
|
||||||
|
counter8:
|
||||||
|
source:
|
||||||
|
- name: counter_output_verilog.v
|
||||||
|
top_module: counter
|
||||||
|
bus_group_file: bus_group.xml
|
|
@ -0,0 +1,7 @@
|
||||||
|
<pin_constraints>
|
||||||
|
<!-- For a given .blif file, we want to assign
|
||||||
|
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||||
|
-->
|
||||||
|
<set_io pin="op_reset[0]" net="reset"/>
|
||||||
|
</pin_constraints>
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# 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/auto_bus_group_example_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
|
||||||
|
openfpga_verilog_port_mapping=--explicit_port_mapping
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
# Yosys script parameters
|
||||||
|
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v
|
||||||
|
bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v
|
||||||
|
bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt
|
||||||
|
bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v
|
||||||
|
bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v
|
||||||
|
bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36
|
||||||
|
bench_read_verilog_options_common = -nolatches
|
||||||
|
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys
|
||||||
|
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys
|
||||||
|
|
||||||
|
bench0_top = counter
|
||||||
|
bench0_openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints_reset.xml
|
||||||
|
bench0_openfpga_bus_group_file=bus_group.xml
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
||||||
|
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -1,6 +1,7 @@
|
||||||
envyaml==1.0.201125
|
envyaml==1.0.201125
|
||||||
humanize==3.1.0
|
humanize==3.1.0
|
||||||
coloredlogs==9.1
|
coloredlogs==9.1
|
||||||
|
pyverilog
|
||||||
|
|
||||||
# Python linter and formatter
|
# Python linter and formatter
|
||||||
click==8.0.2 # Our version of black needs an older version of click (https://stackoverflow.com/questions/71673404/importerror-cannot-import-name-unicodefun-from-click)
|
click==8.0.2 # Our version of black needs an older version of click (https://stackoverflow.com/questions/71673404/importerror-cannot-import-name-unicodefun-from-click)
|
||||||
|
|
Loading…
Reference in New Issue