Add command to generate repack design constraints

This commit is contained in:
Duck Deux 2024-11-06 05:47:04 -08:00
parent 0714ccf608
commit ccfbb40d7d
2 changed files with 167 additions and 0 deletions

View File

@ -8,11 +8,47 @@
*******************************************************************/ *******************************************************************/
#include "openfpga_bitstream_template.h" #include "openfpga_bitstream_template.h"
#include "openfpga_repack_template.h" #include "openfpga_repack_template.h"
#include "openfpga_gen_repack_constraints_template.h"
#include "shell.h" #include "shell.h"
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
/********************************************************************
* - Add a command to Shell environment: gen_repack_constraints
* - Add associated options
* - Add command dependency
*******************************************************************/
template <class T>
ShellCommandId add_gen_repack_constraints_command_template(
openfpga::Shell<T>& shell, const ShellCommandClassId& cmd_class_id,
const std::vector<ShellCommandId>& dependent_cmds, const bool& hidden) {
Command shell_cmd("gen_repack_constraints");
/* Add an option '--pcf' */
CommandOptionId opt_pcf =
shell_cmd.add_option("pcf", false, "Path to the pcf file");
shell_cmd.set_option_require_value(opt_pcf,
openfpga::OPT_STRING);
/* Add an option '--file' */
CommandOptionId opt_file =
shell_cmd.add_option("file", false, "Path to the output file");
shell_cmd.set_option_require_value(opt_file,
openfpga::OPT_STRING);
/* Add command 'gen_repack_constraints' to the Shell */
ShellCommandId shell_cmd_id = shell.add_command(
shell_cmd, "Generate a repack design constraints file from a PCF file", hidden);
shell.set_command_class(shell_cmd_id, cmd_class_id);
shell.set_command_execute_function(shell_cmd_id, gen_repack_constraints_template<T>);
/* Add command dependency to the Shell */
shell.set_command_dependency(shell_cmd_id, dependent_cmds);
return shell_cmd_id;
}
/******************************************************************** /********************************************************************
* - Add a command to Shell environment: repack * - Add a command to Shell environment: repack
* - Add associated options * - Add associated options
@ -298,6 +334,10 @@ void add_bitstream_command_templates(openfpga::Shell<T>& shell,
ShellCommandClassId openfpga_bitstream_cmd_class = ShellCommandClassId openfpga_bitstream_cmd_class =
shell.add_command_class("FPGA-Bitstream"); shell.add_command_class("FPGA-Bitstream");
/********************************
* Command 'gen_repack_constraints' */
add_gen_repack_constraints_command_template(shell, openfpga_bitstream_cmd_class, std::vector<ShellCommandId>(), hidden);
/******************************** /********************************
* Command 'repack' * Command 'repack'
*/ */

View File

@ -0,0 +1,127 @@
#pragma once
#include "command.h"
#include "command_context.h"
#include "command_exit_codes.h"
#include "openfpga_port.h"
#include "openfpga_port_parser.h"
#include "pcf_reader.h"
#include "repack_design_constraints.h"
#include "vtr_log.h"
#include "write_xml_repack_design_constraints.h"
#include "globals.h"
/* begin namespace openfpga */
namespace openfpga {
static inline RepackDesignConstraints gen_repack_constraints(openfpga::PcfData* pcf_data){
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& atom_ctx = g_vpr_ctx.atom();
auto& clb_nlist = cluster_ctx.clb_nlist;
/* 1. Get unique pb_types, clock pins and clock nets from clb_nlist.blocks */
std::set<std::string> pb_type_names;
std::set<BasicPort> clock_pins;
std::set<std::string> clock_nets;
for (auto block_id : clb_nlist.blocks()) {
auto pb = clb_nlist.block_pb(block_id);
auto pb_type = pb->pb_graph_node->pb_type;
pb_type_names.insert(pb_type->name);
int port_index = 0;
for (int i = 0; i < pb_type->num_ports; i++) {
auto& port = pb_type->ports[i];
if(!port.is_clock)
continue;
for (int j = 0; j < port.num_pins; j++) {
auto& pin = pb->pb_graph_node->clock_pins[port_index][j];
std::string pin_name = std::string(port.name) + "[" + std::to_string(j) + "]";
openfpga::PortParser port_parser(pin_name);
clock_pins.insert(port_parser.port());
int node_index = pin.pin_count_in_cluster;
if(pb->pb_route.count(node_index)){
AtomNetId net_id = pb->pb_route[node_index].atom_net_id;
std::string net_name = atom_ctx.nlist.net_name(net_id);
clock_nets.insert(net_name);
}
}
port_index++;
}
}
std::vector<std::pair<std::string, BasicPort>> matches;
/* First match nets & pins from the pcf file */
if(pcf_data){
for (const PcfIoConstraintId& io_id : pcf_data->io_constraints()) {
std::string net = pcf_data->io_net(io_id);
BasicPort pin = pcf_data->io_pin(io_id);
if(!(clock_nets.count(net) && clock_pins.count(pin)))
continue;
matches.push_back({net, pin});
clock_nets.erase(net);
clock_pins.erase(pin);
}
}
/* Match the rest in an arbitrary way */
for(auto net: clock_nets){
VTR_ASSERT_MSG(!clock_pins.empty(), "Not enough clock pins for clocks in the design");
auto first_available_pin = *clock_pins.begin();
matches.push_back({net, first_available_pin});
clock_pins.erase(first_available_pin);
}
/* 3. Create the design constraints */
RepackDesignConstraints out;
for(auto pb_type: pb_type_names){
for(auto [net, pin]: matches){
auto id = out.create_design_constraint(RepackDesignConstraints::PIN_ASSIGNMENT);
out.set_pb_type(id, pb_type);
out.set_net(id, net);
out.set_pin(id, pin);
}
}
return out;
}
/********************************************************************
* Top-level function to generate a repack_design_constraints.xml file
* from either a .pcf file or vpr context
*******************************************************************/
template <class T>
int gen_repack_constraints_template(const Command& cmd,
const CommandContext& cmd_context) {
CommandOptionId opt_pcf = cmd.option("pcf");
CommandOptionId opt_file = cmd.option("file");
std::string out_fname = cmd_context.option_value(cmd, opt_file);
RepackDesignConstraints constraints;
if (cmd_context.option_enable(cmd, opt_pcf)) {
std::string pcf_fname = cmd_context.option_value(cmd, opt_pcf);
openfpga::PcfData pcf_data;
openfpga::read_pcf(pcf_fname.c_str(), pcf_data);
VTR_LOG("[gen_repack_constraints] Read the design constraints from a pcf file: %s.\n",
pcf_fname.c_str());
if (!pcf_data.validate()) {
VTR_LOG_ERROR("[gen_repack_constraints] PCF contains invalid I/O assignment!\n");
return CMD_EXEC_FATAL_ERROR;
} else {
VTR_LOG("[gen_repack_constraints] PCF basic check passed\n");
}
constraints = gen_repack_constraints(&pcf_data);
} else {
constraints = gen_repack_constraints(NULL);
}
write_xml_repack_design_constraints(out_fname.c_str(), constraints);
return CMD_EXEC_SUCCESS;
}
} /* end namespace openfpga */