133 lines
4.8 KiB
C++
133 lines
4.8 KiB
C++
/******************************************************************************
|
|
* Inspired from https://github.com/genbtc/VerilogPCFparser
|
|
******************************************************************************/
|
|
#include <sstream>
|
|
|
|
/* Headers from vtrutil library */
|
|
#include "vtr_assert.h"
|
|
#include "vtr_log.h"
|
|
#include "vtr_time.h"
|
|
|
|
/* Headers from openfpgautil library */
|
|
#include "openfpga_digest.h"
|
|
#include "pcf2place.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/********************************************************************
|
|
* Generate a .place file with the a few inputs
|
|
*
|
|
* Return 0 if successful
|
|
* Return 1 if there are serious errors
|
|
*******************************************************************/
|
|
int pcf2place(const PcfData& pcf_data,
|
|
const std::vector<std::string>& input_nets,
|
|
const std::vector<std::string>& output_nets,
|
|
const IoPinTable& io_pin_table,
|
|
const IoLocationMap& io_location_map, IoNetPlace& io_net_place) {
|
|
vtr::ScopedStartFinishTimer timer("Convert PCF data to VPR I/O place data");
|
|
|
|
int num_err = 0;
|
|
|
|
/* TODO: Validate pcf data, blif_head and io_pin_table
|
|
* - there are no duplicated pin assignment in pcf
|
|
* - the pin direction in io_pin_table matches the pin type defined in blif
|
|
*/
|
|
if (!pcf_data.validate()) {
|
|
VTR_LOG_ERROR("PCF contains invalid I/O assignment!\n");
|
|
return 1;
|
|
} else {
|
|
VTR_LOG("PCF basic check passed\n");
|
|
}
|
|
|
|
/* Map from location to net */
|
|
std::map<std::array<size_t, 3>, std::string> net_map;
|
|
/* Build the I/O place */
|
|
for (const PcfIoConstraintId& io_id : pcf_data.io_constraints()) {
|
|
/* Find the net name */
|
|
std::string net = pcf_data.io_net(io_id);
|
|
/* Find the external pin name */
|
|
BasicPort ext_pin = pcf_data.io_pin(io_id);
|
|
/* Find the pin direction from blif reader */
|
|
IoPinTable::e_io_direction pin_direction = IoPinTable::NUM_IO_DIRECTIONS;
|
|
if (input_nets.end() !=
|
|
std::find(input_nets.begin(), input_nets.end(), net)) {
|
|
pin_direction = IoPinTable::INPUT;
|
|
} else if (output_nets.end() !=
|
|
std::find(output_nets.begin(), output_nets.end(), net)) {
|
|
pin_direction = IoPinTable::OUTPUT;
|
|
} else {
|
|
/* Cannot find the pin, error out! */
|
|
VTR_LOG_ERROR(
|
|
"Net '%s' from .pcf is neither defined as input nor output in .blif!\n",
|
|
net.c_str());
|
|
num_err++;
|
|
continue;
|
|
}
|
|
/* Find the internal pin name from pin table, currently we only support
|
|
* 1-to-1 mapping */
|
|
auto int_pin_ids = io_pin_table.find_internal_pin(ext_pin, pin_direction);
|
|
if (0 == int_pin_ids.size()) {
|
|
VTR_LOG_ERROR(
|
|
"Cannot find any internal pin that net '%s' is mapped through an "
|
|
"external pin '%s[%lu]'!\n",
|
|
net.c_str(), ext_pin.get_name().c_str(), ext_pin.get_lsb());
|
|
num_err++;
|
|
continue;
|
|
} else if (1 < int_pin_ids.size()) {
|
|
VTR_LOG_ERROR(
|
|
"Found multiple internal pins that net '%s' is mapped through an "
|
|
"external pin '%s[%lu]'! Please double check your pin table!\n",
|
|
net.c_str(), ext_pin.get_name().c_str(), ext_pin.get_lsb());
|
|
for (auto int_pin_id : int_pin_ids) {
|
|
VTR_LOG("%s[%ld]\n",
|
|
io_pin_table.internal_pin(int_pin_id).get_name().c_str(),
|
|
io_pin_table.internal_pin(int_pin_id).get_lsb());
|
|
}
|
|
num_err++;
|
|
continue;
|
|
}
|
|
VTR_ASSERT(1 == int_pin_ids.size());
|
|
BasicPort int_pin = io_pin_table.internal_pin(int_pin_ids[0]);
|
|
/* Find the coordinate from io location map */
|
|
size_t x = io_location_map.io_x(int_pin);
|
|
size_t y = io_location_map.io_y(int_pin);
|
|
size_t z = io_location_map.io_z(int_pin);
|
|
/* Sanity check */
|
|
if (size_t(-1) == x || size_t(-1) == y || size_t(-1) == z) {
|
|
VTR_LOG_ERROR(
|
|
"Invalid coordinate (%ld, %ld, %ld) found for net '%s' mapped to an "
|
|
"external pin '%s[%lu]' through an internal pin '%s[%lu]'!\n",
|
|
x, y, z, net.c_str(), ext_pin.get_name().c_str(), ext_pin.get_lsb(),
|
|
int_pin.get_name().c_str(), int_pin.get_lsb());
|
|
continue;
|
|
}
|
|
|
|
std::array<size_t, 3> loc = {x, y, z};
|
|
auto itr = net_map.find(loc);
|
|
if (itr == net_map.end()) {
|
|
net_map.insert({loc, net});
|
|
} else {
|
|
VTR_LOG_ERROR(
|
|
"Illegal pin constraint: Two nets '%s' and '%s' are mapped to the I/O "
|
|
"pin '%s[%lu]' which belongs to the same coordinate (%ld, %ld, %ld)!\n",
|
|
itr->second.c_str(), net.c_str(), int_pin.get_name().c_str(),
|
|
int_pin.get_lsb(), x, y, z);
|
|
num_err++;
|
|
continue;
|
|
}
|
|
|
|
/* Add a fixed prefix to net namei, this is hard coded by VPR */
|
|
if (IoPinTable::OUTPUT == pin_direction) {
|
|
net = "out:" + net;
|
|
}
|
|
/* Add the information to I/O place data */
|
|
io_net_place.set_net_coord(net, x, y, z);
|
|
}
|
|
|
|
return num_err;
|
|
}
|
|
|
|
} /* end namespace openfpga */
|