Merge pull request #732 from lnis-uofu/pcf_refactor

Refactor ``libpcf`` to integrate ``libpinconstrain``, ``librepackdc``; Rewrite ``libpinconstrain``
This commit is contained in:
tangxifan 2022-07-28 22:43:08 -07:00 committed by GitHub
commit 300e1bcaba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 3852 additions and 1292 deletions

View File

@ -24,6 +24,12 @@ OpenFPGA widely uses XML format for interchangable files
io_mapping_file
io_info_file
bitstream_distribution_file
bus_group_file
pcf_file
pin_table_file

View File

@ -1,7 +1,9 @@
.. _file_format_io_info_file:
I/O Information File (.xml)
-----------------------
---------------------------
.. note:: This file is in a different usage than the I/O mapping file (see details in :ref:`file_format_io_mapping_file`)
The I/O information file aims to show

View File

@ -0,0 +1,24 @@
.. _file_format_pcf_file:
Pin Constraints File (.pcf)
---------------------------
.. note:: This file is in a different usage than the Pin Constraints File in XML format (see details in :ref:`file_format_pin_constraints_file`)
The PCF file is the file which **users** should craft to assign their I/O constraints
An example of the file is shown as follows.
.. code-block:: xml
set_io a pad_fpga_io[0]
set_io b[0] pad_fpga_io[4]
set_io c[1] pad_fpga_io[6]
.. option:: set_io <net> <pin>
Assign a net (defined as an input or output in users' HDL design) to a specific pin of an FPGA device (typically a packaged chip).
.. note:: The net should be single-bit and match the port declaration of the top-module in users' HDL design
.. note:: FPGA devices have different pin names, depending their naming rules. Please contact your vendor about details.

View File

@ -3,7 +3,8 @@
Pin Constraints File (.xml)
---------------------------
The *Pin Constraints File* (PCF) aims to create pin binding between an implementation and an FPGA fabric
The *Pin Constraints File* (PCF) aims to create pin binding between an implementation and an FPGA fabric.
It is a common file format used by FPGA vendors, for example, `QuickLogic<https://docs.verilogtorouting.org/en/latest/vpr/file_formats/#placement-file-format-place>`_.
An example of design constraints is shown as follows.

View File

@ -0,0 +1,48 @@
.. _file_format_pin_table_file:
Pin Table File (.csv)
---------------------
.. note:: This file is typically a spreadsheet provided by FPGA vendors. Please contact your vendor for the exact file.
.. note:: OpenFPGA will not include or guarantee the correctness of the file!!!
The pin table file is the file which describes the pin mapping between a chip and an FPGA inside the chip.
An example of the file is shown as follows.
.. code-block:: xml
orientation,row,col,pin_num_in_cell,port_name,mapped_pin,GPIO_type,Associated Clock,Clock Edge
TOP,,,,gfpga_pad_IO_A2F[0],pad_fpga_io[0],,,
TOP,,,,gfpga_pad_IO_F2A[0],pad_fpga_io[0],,,
TOP,,,,gfpga_pad_IO_A2F[4],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_F2A[4],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_A2F[8],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_F2A[8],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_A2F[31],pad_fpga_io[3],,,
TOP,,,,gfpga_pad_IO_F2A[31],pad_fpga_io[3],,,
RIGHT,,,,gfpga_pad_IO_A2F[32],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_F2A[32],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_A2F[40],pad_fpga_io[5],,,
RIGHT,,,,gfpga_pad_IO_F2A[40],pad_fpga_io[5],,,
BOTTOM,,,,gfpga_pad_IO_A2F[64],pad_fpga_io[6],,,
BOTTOM,,,,gfpga_pad_IO_F2A[64],pad_fpga_io[6],,,
LEFT,,,,gfpga_pad_IO_F2A[127],pad_fpga_io[7],,,
LEFT,,,,gfpga_pad_IO_A2F[127],pad_fpga_io[7],,,
An pin table may serve in various purposes. However, for OpenFPGA, the following attributes are required
.. option:: orientation
Specify on which side the pin locates
.. option:: port_name
Specify the port name of the FPGA fabric
.. option:: mapped_pin
Specify the pin name of the FPGA chip
.. warning:: Currently, the direction of the port is inferred by the ``port_name``. A postfix of ``A2F`` indicates an input port, while a postfix of ``F2A`` indicates an output port.

View File

@ -218,6 +218,8 @@ write_fabric_hierarchy
.. note:: This file is designed for hierarchical PnR flow, which requires the tree of Multiple-Instanced-Blocks (MIBs).
.. _openfpga_setup_commands_write_fabric_io_info:
write_fabric_io_info
~~~~~~~~~~~~~~~~~~~~
@ -236,3 +238,36 @@ write_fabric_io_info
Show verbose log
.. note:: This file is designed for pin constraint file conversion.
pcf2place
~~~~~~~~~
Convert a Pin Constraint File (.pcf, see details in :ref:`file_format_pcf_file`) to a `placement file <https://docs.verilogtorouting.org/en/latest/vpr/file_formats/#placement-file-format-place>`_)
.. option:: --pcf <string>
Specify the path to the users' pin constraint file
.. option:: --blif <string>
Specify the path to the users' post-synthesis netlist
.. option:: --fpga_io_map <string>
Specify the path to the FPGA I/O location. Achieved by the command :ref:`openfpga_setup_commands_write_fabric_io_info`
.. option:: --pin_table <string>
Specify the path to the pin table file, which describes the pin mapping between chip I/Os and FPGA I/Os. See details in :ref:`file_format_pin_table_file`
.. option:: --fpga_fix_pins <string>
Specify the path to the placement file which will be outputted by running this command
.. option:: --no_time_stamp
Do not print time stamp in bitstream files
.. option:: --verbose
Show verbose log

View File

@ -4,8 +4,6 @@ add_subdirectory(libopenfpgashell)
add_subdirectory(libarchopenfpga)
add_subdirectory(libopenfpgautil)
add_subdirectory(libfabrickey)
add_subdirectory(librepackdc)
add_subdirectory(libfpgabitstream)
add_subdirectory(libpcf)
add_subdirectory(libbusgroup)
add_subdirectory(libpinconstrain)

View File

@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.9)
project("libpcf")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
file(GLOB_RECURSE LIB_SOURCES src/*/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Remove test executable from library
@ -20,8 +20,10 @@ set_target_properties(libpcf PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Specify link-time dependancies
target_link_libraries(libpcf
libopenfpgautil
libarchfpga
libarchopenfpga
libvtrutil
libblifparse
libpugixml
libpugiutil)

View File

@ -0,0 +1,8 @@
.model and2
.inputs a b
.outputs c
.names a b c
11 1
.end

View File

@ -0,0 +1,40 @@
<!--
- FPGA Fabric I/O Information
- Generated by OpenFPGA
- Date: Tue Jul 26 13:54:26 2022
-->
<io_coordinates>
<io pad="gfpga_pad_GPIO_PAD[24]" x="0" y="1" z="0"/>
<io pad="gfpga_pad_GPIO_PAD[25]" x="0" y="1" z="1"/>
<io pad="gfpga_pad_GPIO_PAD[26]" x="0" y="1" z="2"/>
<io pad="gfpga_pad_GPIO_PAD[27]" x="0" y="1" z="3"/>
<io pad="gfpga_pad_GPIO_PAD[28]" x="0" y="1" z="4"/>
<io pad="gfpga_pad_GPIO_PAD[29]" x="0" y="1" z="5"/>
<io pad="gfpga_pad_GPIO_PAD[30]" x="0" y="1" z="6"/>
<io pad="gfpga_pad_GPIO_PAD[31]" x="0" y="1" z="7"/>
<io pad="gfpga_pad_GPIO_PAD[16]" x="1" y="0" z="0"/>
<io pad="gfpga_pad_GPIO_PAD[17]" x="1" y="0" z="1"/>
<io pad="gfpga_pad_GPIO_PAD[18]" x="1" y="0" z="2"/>
<io pad="gfpga_pad_GPIO_PAD[19]" x="1" y="0" z="3"/>
<io pad="gfpga_pad_GPIO_PAD[20]" x="1" y="0" z="4"/>
<io pad="gfpga_pad_GPIO_PAD[21]" x="1" y="0" z="5"/>
<io pad="gfpga_pad_GPIO_PAD[22]" x="1" y="0" z="6"/>
<io pad="gfpga_pad_GPIO_PAD[23]" x="1" y="0" z="7"/>
<io pad="gfpga_pad_GPIO_PAD[0]" x="1" y="2" z="0"/>
<io pad="gfpga_pad_GPIO_PAD[1]" x="1" y="2" z="1"/>
<io pad="gfpga_pad_GPIO_PAD[2]" x="1" y="2" z="2"/>
<io pad="gfpga_pad_GPIO_PAD[3]" x="1" y="2" z="3"/>
<io pad="gfpga_pad_GPIO_PAD[4]" x="1" y="2" z="4"/>
<io pad="gfpga_pad_GPIO_PAD[5]" x="1" y="2" z="5"/>
<io pad="gfpga_pad_GPIO_PAD[6]" x="1" y="2" z="6"/>
<io pad="gfpga_pad_GPIO_PAD[7]" x="1" y="2" z="7"/>
<io pad="gfpga_pad_GPIO_PAD[8]" x="2" y="1" z="0"/>
<io pad="gfpga_pad_GPIO_PAD[9]" x="2" y="1" z="1"/>
<io pad="gfpga_pad_GPIO_PAD[10]" x="2" y="1" z="2"/>
<io pad="gfpga_pad_GPIO_PAD[11]" x="2" y="1" z="3"/>
<io pad="gfpga_pad_GPIO_PAD[12]" x="2" y="1" z="4"/>
<io pad="gfpga_pad_GPIO_PAD[13]" x="2" y="1" z="5"/>
<io pad="gfpga_pad_GPIO_PAD[14]" x="2" y="1" z="6"/>
<io pad="gfpga_pad_GPIO_PAD[15]" x="2" y="1" z="7"/>
</io_coordinates>

View File

@ -0,0 +1,18 @@
<io_coordinates>
<io pad="gfpga_pad_IO_A2F[0]" x="1" y="2" z="0"/>
<io pad="gfpga_pad_IO_F2A[0]" x="1" y="2" z="1"/>
<io pad="gfpga_pad_IO_A2F[1]" x="1" y="2" z="2"/>
<io pad="gfpga_pad_IO_F2A[1]" x="1" y="2" z="3"/>
<io pad="gfpga_pad_IO_A2F[2]" x="1" y="2" z="4"/>
<io pad="gfpga_pad_IO_F2A[2]" x="1" y="2" z="5"/>
<io pad="gfpga_pad_IO_A2F[3]" x="1" y="2" z="6"/>
<io pad="gfpga_pad_IO_F2A[3]" x="1" y="2" z="7"/>
<io pad="gfpga_pad_IO_A2F[4]" x="2" y="1" z="0"/>
<io pad="gfpga_pad_IO_F2A[4]" x="2" y="1" z="1"/>
<io pad="gfpga_pad_IO_A2F[5]" x="2" y="1" z="2"/>
<io pad="gfpga_pad_IO_F2A[5]" x="2" y="1" z="3"/>
<io pad="gfpga_pad_IO_A2F[6]" x="2" y="1" z="4"/>
<io pad="gfpga_pad_IO_F2A[6]" x="2" y="1" z="5"/>
<io pad="gfpga_pad_IO_A2F[7]" x="2" y="1" z="6"/>
<io pad="gfpga_pad_IO_F2A[7]" x="2" y="1" z="7"/>
</io_coordinates>

View File

@ -2,6 +2,7 @@
* Memember functions for data structure IoLocationMap
******************************************************************************/
/* Headers from vtrutil library */
#include <algorithm>
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
@ -21,24 +22,54 @@ size_t IoLocationMap::io_index(const size_t& x,
const size_t& y,
const size_t& z,
const std::string& io_port_name) const {
if (x >= io_indices_.size()) {
std::array<size_t, 3> coord = {x, y, z};
auto result = io_indices_.find(coord);
if (result == io_indices_.end()) {
return size_t(-1);
}
if (y >= io_indices_[x].size()) {
return size_t(-1);
for (const BasicPort& candidate : result->second) {
if (candidate.get_name() == io_port_name) {
/* First found, first return. This may create bugs when FPGA architecture are more flexible
* FIXME: However, we should not have multiple I/O in the same name, mapped to the same coordindate
* For example, PAD[0] -> (1, 0, 1) and PAD[1] -> (1, 0, 1)
*/
return candidate.get_lsb();
}
}
return size_t(-1);
}
if (z >= io_indices_[x][y].size()) {
return size_t(-1);
size_t IoLocationMap::io_x(const BasicPort& io_port) const {
for (auto pair : io_indices_) {
for (const BasicPort& candidate : pair.second) {
if (candidate == io_port) {
return pair.first[0];
}
}
}
return size_t(-1);
}
auto result = io_indices_[x][y][z].find(io_port_name);
if (result == io_indices_[x][y][z].end()) {
return size_t(-1);
size_t IoLocationMap::io_y(const BasicPort& io_port) const {
for (auto pair : io_indices_) {
for (const BasicPort& candidate : pair.second) {
if (candidate == io_port) {
return pair.first[1];
}
}
}
return size_t(-1);
}
return result->second;
size_t IoLocationMap::io_z(const BasicPort& io_port) const {
for (auto pair : io_indices_) {
for (const BasicPort& candidate : pair.second) {
if (candidate == io_port) {
return pair.first[2];
}
}
}
return size_t(-1);
}
void IoLocationMap::set_io_index(const size_t& x,
@ -46,19 +77,18 @@ void IoLocationMap::set_io_index(const size_t& x,
const size_t& z,
const std::string& io_port_name,
const size_t& io_index) {
if (x >= io_indices_.size()) {
io_indices_.resize(x + 1);
std::array<size_t, 3> coord = {x, y, z};
BasicPort port_to_add(io_port_name, io_index, io_index);
auto result = io_indices_.find(coord);
if (result != io_indices_.end()) {
if (io_indices_.at(coord).end() != std::find(io_indices_.at(coord).begin(), io_indices_.at(coord).end(), port_to_add)) {
VTR_LOG_WARN("Attempt to add duplicated io '%s[%lu]' to coordinate (%lu, %lu, %lu)! Skip to save memory\n",
io_port_name.c_str(), io_index,
x, y, z);
}
}
if (y >= io_indices_[x].size()) {
io_indices_[x].resize(y + 1);
}
if (z >= io_indices_[x][y].size()) {
io_indices_[x][y].resize(z + 1);
}
io_indices_[x][y][z][io_port_name] = io_index;
io_indices_[coord].push_back(port_to_add);
}
int IoLocationMap::write_to_xml_file(const std::string& fname,
@ -106,19 +136,15 @@ int IoLocationMap::write_to_xml_file(const std::string& fname,
size_t io_cnt = 0;
/* Walk through the fabric I/O location map data structure */
for (size_t x = 0; x < io_indices_.size(); ++x) {
for (size_t y = 0; y < io_indices_[x].size(); ++y) {
for (size_t z = 0; z < io_indices_[x][y].size(); ++z) {
for (const auto& name_id_pair : io_indices_[x][y][z]) {
fp << "\t" << "<io pad=\"" << name_id_pair.first << "[" << name_id_pair.second << "]\"";
fp << " " << "x=\"" << x << "\"";
fp << " " << "y=\"" << y << "\"";
fp << " " << "z=\"" << z << "\"";
fp << "/>";
fp << "\n";
io_cnt++;
}
}
for (auto pair : io_indices_) {
for (const BasicPort& port : pair.second) {
fp << "\t" << "<io pad=\"" << port.get_name().c_str() << "[" << port.get_lsb() << "]\"";
fp << " " << "x=\"" << pair.first[0] << "\"";
fp << " " << "y=\"" << pair.first[1] << "\"";
fp << " " << "z=\"" << pair.first[2] << "\"";
fp << "/>";
fp << "\n";
io_cnt++;
}
}

View File

@ -8,6 +8,7 @@
#include <vector>
#include <string>
#include <map>
#include "openfpga_port.h"
/* Begin namespace openfpga */
namespace openfpga {
@ -34,6 +35,9 @@ class IoLocationMap {
const size_t& y,
const size_t& z,
const std::string& io_port_name) const;
size_t io_x(const BasicPort& io_port) const;
size_t io_y(const BasicPort& io_port) const;
size_t io_z(const BasicPort& io_port) const;
public: /* Public mutators */
void set_io_index(const size_t& x,
const size_t& y,
@ -45,8 +49,10 @@ class IoLocationMap {
const bool& include_time_stamp,
const bool& verbose) const;
private: /* Internal Data */
/* I/O index fast lookup by [x][y][z] location */
std::vector<std::vector<std::vector<std::map<std::string, size_t>>>> io_indices_;
/* I/O index fast lookup by [x][y][z] location
* Note that multiple I/Os may be assigned to the same coordinate!
*/
std::map<std::array<size_t, 3>, std::vector<BasicPort>> io_indices_;
};
} /* End namespace openfpga*/

View File

@ -0,0 +1,126 @@
/******************************************************************************
* Memember functions for data structure IoNetPlace
******************************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
#include "io_net_place.h"
/* begin namespace openfpga */
namespace openfpga {
/**************************************************
* Public Accessors
*************************************************/
size_t IoNetPlace::io_x(const std::string& net) const {
auto result = io_coords_.find(net);
if (result == io_coords_.end()) {
return size_t(-1);
}
return result->second[0];
}
size_t IoNetPlace::io_y(const std::string& net) const {
auto result = io_coords_.find(net);
if (result == io_coords_.end()) {
return size_t(-1);
}
return result->second[1];
}
size_t IoNetPlace::io_z(const std::string& net) const {
auto result = io_coords_.find(net);
if (result == io_coords_.end()) {
return size_t(-1);
}
return result->second[2];
}
void IoNetPlace::set_net_coord(const std::string& net,
const size_t& x,
const size_t& y,
const size_t& z) {
/* Warn when there is an attempt to overwrite */
auto result = io_coords_.find(net);
if (result != io_coords_.end()) {
VTR_LOG_WARN("Overwrite net '%s' coordinate from (%lu, %lu, %lu) to (%lu, %lu, %lu)!\n",
net.c_str(),
result->second[0], result->second[1], result->second[2],
x, y, z);
}
io_coords_[net][0] = x;
io_coords_[net][1] = y;
io_coords_[net][2] = z;
}
int IoNetPlace::write_to_place_file(const std::string& fname,
const bool& include_time_stamp,
const bool& verbose) const {
std::string timer_message = std::string("Write I/O coordinates to a place file '") + fname + std::string("'");
std::string dir_path = format_dir_path(find_path_dir_name(fname));
/* Create directories */
create_directory(dir_path);
/* Start time count */
vtr::ScopedStartFinishTimer timer(timer_message);
/* Use default name if user does not provide one */
VTR_ASSERT(true != fname.empty());
/* Create a file handler*/
std::fstream fp;
/* Open a file */
fp.open(fname, std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
check_file_stream(fname.c_str(), fp);
int err_code = 0;
/* Write XML head */
fp << "# FPGA Fixed I/O placement file" << std::endl;
fp << "# Generated by OpenFPGA" << std::endl;
auto end = std::chrono::system_clock::now();
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
if (include_time_stamp) {
fp << "# Date: " << std::ctime(&end_time) ;
}
fp << "#Block Name\tx\ty\tz" << std::endl;
fp << "#----------\t-\t-\t-" << std::endl;
size_t io_cnt = 0;
/* Walk through the fabric I/O location map data structure */
for (auto pair : io_coords_) {
fp << pair.first.c_str() << "\t";
fp << pair.second[0] << "\t";
fp << pair.second[1] << "\t";
fp << pair.second[2] << "\n";
io_cnt++;
}
/* close a file */
fp.close();
VTR_LOGV(verbose,
"Outputted %lu I/Os to place file: %s\n",
io_cnt,
fname.c_str());
return err_code;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,53 @@
#ifndef IO_NET_PLACE_H
#define IO_NET_PLACE_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <stddef.h>
#include <vector>
#include <string>
#include <map>
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* I/O net place is a data structure to store the coordinate of each nets
* defined in users' HDL designs on FPGA fabric.
*
* For example:
* netA netB
* | |
* v v
* ioA[0] ioA[1] ioB[0] ioB[1] ioA[2]
* +-----------------+ +--------+--------+ +--------+
* | | | | | | | |
* | I/O | I/O | | I/O | I/O | | I/O |
* | [0][y] | [0][y] | | [1][y] | [1][y] | | [2][y] | ...
* | [0] | [1] | | [0] | [1] | | [0] |
* +-----------------+ +--------+--------+ +--------+
*
*******************************************************************/
class IoNetPlace {
public: /* Public aggregators */
size_t io_x(const std::string& net) const;
size_t io_y(const std::string& net) const;
size_t io_z(const std::string& net) const;
public: /* Writers */
int write_to_place_file(const std::string& fname,
const bool& include_time_stamp,
const bool& verbose) const;
public: /* Public mutators */
void set_net_coord(const std::string& net,
const size_t& x,
const size_t& y,
const size_t& z);
private: /* Internal Data */
/* I/O coordinate fast lookup by net name */
std::map<std::string, std::array<size_t, 3>> io_coords_;
};
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,123 @@
#include <algorithm>
#include "vtr_assert.h"
#include "vtr_log.h"
#include "io_pin_table.h"
/* begin namespace openfpga */
namespace openfpga {
/************************************************************************
* Member functions for class IoPinTable
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
IoPinTable::IoPinTable() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
IoPinTable::io_pin_table_range IoPinTable::pins() const {
return vtr::make_range(pin_ids_.begin(), pin_ids_.end());
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
BasicPort IoPinTable::internal_pin(const IoPinTableId& pin_id) const {
/* validate the pin_id */
VTR_ASSERT(valid_pin_id(pin_id));
return internal_pins_[pin_id];
}
BasicPort IoPinTable::external_pin(const IoPinTableId& pin_id) const {
/* validate the pin_id */
VTR_ASSERT(valid_pin_id(pin_id));
return external_pins_[pin_id];
}
e_side IoPinTable::pin_side(const IoPinTableId& pin_id) const {
/* validate the pin_id */
VTR_ASSERT(valid_pin_id(pin_id));
return pin_sides_[pin_id];
}
IoPinTable::e_io_direction IoPinTable::pin_direction(const IoPinTableId& pin_id) const {
/* validate the pin_id */
VTR_ASSERT(valid_pin_id(pin_id));
return pin_directions_[pin_id];
}
std::vector<IoPinTableId> IoPinTable::find_internal_pin(const BasicPort& ext_pin,
const e_io_direction& pin_direction) const {
std::vector<IoPinTableId> int_pin_ids;
for (auto pin_id : pin_ids_) {
if ((external_pins_[pin_id] == ext_pin) && (pin_directions_[pin_id] == pin_direction)) {
int_pin_ids.push_back(pin_id);
}
}
return int_pin_ids;
}
bool IoPinTable::empty() const {
return 0 == pin_ids_.size();
}
/************************************************************************
* Public Mutators
***********************************************************************/
void IoPinTable::reserve_pins(const size_t& num_pins) {
pin_ids_.reserve(num_pins);
internal_pins_.reserve(num_pins);
external_pins_.reserve(num_pins);
pin_sides_.reserve(num_pins);
pin_directions_.reserve(num_pins);
}
IoPinTableId IoPinTable::create_pin() {
/* Create a new id */
IoPinTableId pin_id = IoPinTableId(pin_ids_.size());
pin_ids_.push_back(pin_id);
internal_pins_.emplace_back();
external_pins_.emplace_back();
pin_sides_.emplace_back(NUM_SIDES);
pin_directions_.emplace_back(NUM_IO_DIRECTIONS);
return pin_id;
}
void IoPinTable::set_internal_pin(const IoPinTableId& pin_id, const BasicPort& pin) {
VTR_ASSERT(valid_pin_id(pin_id));
internal_pins_[pin_id] = pin;
}
void IoPinTable::set_external_pin(const IoPinTableId& pin_id, const BasicPort& pin) {
VTR_ASSERT(valid_pin_id(pin_id));
external_pins_[pin_id] = pin;
}
void IoPinTable::set_pin_side(const IoPinTableId& pin_id, const e_side& side) {
VTR_ASSERT(valid_pin_id(pin_id));
pin_sides_[pin_id] = side;
}
void IoPinTable::set_pin_direction(const IoPinTableId& pin_id, const e_io_direction& direction) {
VTR_ASSERT(valid_pin_id(pin_id));
pin_directions_[pin_id] = direction;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool IoPinTable::valid_pin_id(const IoPinTableId& pin_id) const {
return ( size_t(pin_id) < pin_ids_.size() ) && ( pin_id == pin_ids_[pin_id] );
}
} /* end namespace openfpga */

View File

@ -0,0 +1,112 @@
#ifndef IO_PIN_TABLE_H
#define IO_PIN_TABLE_H
/********************************************************************
* This file include the declaration of pin constraints
*******************************************************************/
#include <string>
#include <map>
#include <array>
/* Headers from vtrutil library */
#include "vtr_vector.h"
#include "vtr_geometry.h"
/* Headers from libarchfpga library */
#include "physical_types.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "io_pin_table_fwd.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* A data structure to describe the I/O pin table for FPGA fabrics
* This data structure may include a number of I/O pins
* each of which contains the following information
* - side: the side which this I/O locates on FPGA perimeter
* - external_pin_name: the name of the external I/O pin (typically on a packaged chip), which is exposed to end-users
* - internal_pin_name: the name of the internal I/O pin (typically inside the chip but on an FPGA fabric), which is defined in FPGA netlists
* - direction: the direction of the internal pin, can be input, output or inout
*
* The following figure illustrates the relationship between external and internal pins.
* FPGA Chip
* +----------------------------------------
* | FPGA fabric
* | +----------------------
* | +----- + |
* CHIP_IO_TOP --->|--->| I/O |--->| FPGA_IN[0]
* (External pin) | | Ctrl | | (internal pin as input)
* | | |<---| FPGA_OUT[1]
* | +------+ | (internal pin as output)
*
* Typical usage:
* --------------
* // Create an object
* IoPinTable io_pin_table;
* // Add a pin
* openfpga::BasicPort ext_pin_info("CHIP_IO_TOP", 1);
* openfpga::BasicPort int_pin_info("FPGA_IN", 1, 1);
* IoPinTableId pin_id = io_pin_table.create_io_pin(int_pin_info, ext_pin_info, TOP, INPUT);
*
*******************************************************************/
class IoPinTable {
public: /* Types */
typedef vtr::vector<IoPinTableId, IoPinTableId>::const_iterator io_pin_table_iterator;
/* Create range */
typedef vtr::Range<io_pin_table_iterator> io_pin_table_range;
/* Logic value */
enum e_io_direction {
INPUT,
OUTPUT,
NUM_IO_DIRECTIONS
};
public: /* Constructors */
IoPinTable();
public: /* Accessors: aggregates */
/* Walk through the internal pins. We do not walk through external pins because they are not unique in the table.
* An external pin may be accessible by two internal pins
*/
io_pin_table_range pins() const;
public: /* Public Accessors: Basic data query */
/* Get the basic information for a pin */
BasicPort internal_pin(const IoPinTableId& pin_id) const;
BasicPort external_pin(const IoPinTableId& pin_id) const;
e_side pin_side(const IoPinTableId& pin_id) const;
e_io_direction pin_direction(const IoPinTableId& pin_id) const;
/* Given an external pin, find all the internal pin that is mapped */
std::vector<IoPinTableId> find_internal_pin(const BasicPort& ext_pin,
const e_io_direction& pin_direction) const;
/* Check if there are any pins */
bool empty() const;
public: /* Public Mutators */
/* Reserve to be memory efficent */
void reserve_pins(const size_t& num_pins);
/* Add a pin to storage */
IoPinTableId create_pin();
/* Set pin attributes */
void set_internal_pin(const IoPinTableId& pin_id, const BasicPort& pin);
void set_external_pin(const IoPinTableId& pin_id, const BasicPort& pin);
void set_pin_side(const IoPinTableId& pin_id, const e_side& side);
void set_pin_direction(const IoPinTableId& pin_id, const e_io_direction& direction);
public: /* Public invalidators/validators */
/* Show if the pin id is a valid for data queries */
bool valid_pin_id(const IoPinTableId& pin_id) const;
private: /* Internal data */
/* Unique ids for each design constraint */
vtr::vector<IoPinTableId, IoPinTableId> pin_ids_;
/* Pin information*/
vtr::vector<IoPinTableId, BasicPort> internal_pins_;
vtr::vector<IoPinTableId, BasicPort> external_pins_;
vtr::vector<IoPinTableId, e_side> pin_sides_;
vtr::vector<IoPinTableId, e_io_direction> pin_directions_;
};
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,22 @@
/************************************************************************
* A header file for IoPinTable class, including critical data declaration
* Please include this file only for using any IoPinTable data structure
* Refer to IoPinTable.h for more details
***********************************************************************/
/************************************************************************
* Create strong id for IoPinTable to avoid illegal type casting
***********************************************************************/
#ifndef IO_PIN_TABLE_FWD_H
#define IO_PIN_TABLE_FWD_H
#include "vtr_strong_id.h"
struct io_pin_table_id_tag;
typedef vtr::StrongId<io_pin_table_id_tag> IoPinTableId;
/* Short declaration of class */
class IoPinTable;
#endif

View File

@ -0,0 +1,110 @@
/******************************************************************************
* Inspired from https://github.com/genbtc/VerilogPCFparser
******************************************************************************/
#include <sstream>
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.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_ERROR("PCF basic check passed\n");
}
/* 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;
}
/* 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 */

View File

@ -0,0 +1,31 @@
#ifndef PCF2PLACE_H
#define PCF2PLACE_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <string>
#include <vector>
#include "pcf_data.h"
#include "io_pin_table.h"
#include "io_location_map.h"
#include "io_net_place.h"
/* Begin namespace openfpga */
namespace openfpga {
/* Generate a .place file with the following input files
* - A Pin Constraint File (.pcf)
* - Input and output lists from a netlist
* - A chip I/O pin table file (.csv)
* - An FPGA I/O location file (.xml)
*/
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);
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,128 @@
#include <algorithm>
#include "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_port_parser.h"
#include "pcf_data.h"
/* Begin namespace openfpga */
namespace openfpga {
/************************************************************************
* Member functions for class PcfData
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
PcfData::PcfData() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
PcfData::pcf_io_constraint_range PcfData::io_constraints() const {
return vtr::make_range(io_constraint_ids_.begin(), io_constraint_ids_.end());
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
openfpga::BasicPort PcfData::io_pin(const PcfIoConstraintId& io_id) const {
/* validate the io_id */
VTR_ASSERT(valid_io_constraint_id(io_id));
return io_constraint_pins_[io_id];
}
std::string PcfData::io_net(const PcfIoConstraintId& io_id) const {
/* validate the io_id */
VTR_ASSERT(valid_io_constraint_id(io_id));
return io_constraint_nets_[io_id];
}
bool PcfData::empty() const {
return 0 == io_constraint_ids_.size();
}
bool PcfData::validate() const {
size_t num_err = 0;
/* In principle, we do not expect duplicated assignment: 1 net -> 2 pins */
std::map<std::string, BasicPort> net2pin;
for (const PcfIoConstraintId& io_id : io_constraints()) {
std::string curr_net = io_constraint_nets_[io_id];
BasicPort curr_pin = io_constraint_pins_[io_id];
auto result = net2pin.find(curr_net);
if (result != net2pin.end()) {
/* Found one nets assigned to two pins, throw warning */
VTR_LOG_WARN("Net '%s' is assigned to two pins '%s[%lu]' and '%s[%lu]'!\n",
curr_net.c_str(),
curr_pin.get_name().c_str(), curr_pin.get_lsb(),
result->second.get_name().c_str(), result->second.get_lsb());
}
net2pin[curr_net] = curr_pin;
}
/* We should not have duplicated pins in assignment: 1 pin -> 2 nets */
std::map<BasicPort, std::string> pin2net;
for (const PcfIoConstraintId& io_id : io_constraints()) {
std::string curr_net = io_constraint_nets_[io_id];
BasicPort curr_pin = io_constraint_pins_[io_id];
auto result = pin2net.find(curr_pin);
if (result != pin2net.end()) {
/* Found one pin assigned to two nets, this is definitely an error */
VTR_LOG_ERROR("Pin '%s[%lu]' is assigned to two nets '%s' and '%s'!\n",
curr_pin.get_name().c_str(), curr_pin.get_lsb(),
result->second.c_str(), curr_net.c_str());
}
pin2net[curr_pin] = curr_net;
}
if (num_err) {
return false;
}
return true;
}
/************************************************************************
* Public Mutators
***********************************************************************/
void PcfData::reserve_io_constraints(const size_t& num_io_constraints) {
io_constraint_ids_.reserve(num_io_constraints);
io_constraint_pins_.reserve(num_io_constraints);
io_constraint_nets_.reserve(num_io_constraints);
}
PcfIoConstraintId PcfData::create_io_constraint() {
/* Create a new id */
PcfIoConstraintId io_id = PcfIoConstraintId(io_constraint_ids_.size());
io_constraint_ids_.push_back(io_id);
io_constraint_pins_.emplace_back();
io_constraint_nets_.emplace_back();
return io_id;
}
void PcfData::set_io_net(const PcfIoConstraintId& io_id,
const std::string& net) {
VTR_ASSERT(valid_io_constraint_id(io_id));
io_constraint_nets_[io_id] = net;
}
void PcfData::set_io_pin(const PcfIoConstraintId& io_id,
const std::string& pin) {
VTR_ASSERT(valid_io_constraint_id(io_id));
PortParser port_parser(pin);
io_constraint_pins_[io_id] = port_parser.port();
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool PcfData::valid_io_constraint_id(const PcfIoConstraintId& io_id) const {
return ( size_t(io_id) < io_constraint_ids_.size() ) && ( io_id == io_constraint_ids_[io_id] );
}
} /* End namespace openfpga*/

View File

@ -0,0 +1,92 @@
#ifndef PCF_DATA_H
#define PCF_DATA_H
/********************************************************************
* This file include the declaration of pcf data
*******************************************************************/
#include <string>
#include <map>
#include <array>
/* Headers from vtrutil library */
#include "vtr_vector.h"
#include "vtr_geometry.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "pcf_data_fwd.h"
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* A data structure to constain PCF data
* This data structure may include a number of design constraints
* - I/O constraint, for instance, force a net to be mapped to specific pin
*
* Typical usage:
* --------------
* // Create an object
* PcfData pcf_data;
* // Add a constraint
* PcfIoConstraintId io_id = pcf_data.create_io_constraint();
* pcf_data.set_io_net(io_id, net_name);
* pcf_data.set_io_pin(io_id, pin_name);
*
*******************************************************************/
class PcfData {
public: /* Types */
typedef vtr::vector<PcfIoConstraintId, PcfIoConstraintId>::const_iterator pcf_io_constraint_iterator;
/* Create range */
typedef vtr::Range<pcf_io_constraint_iterator> pcf_io_constraint_range;
public: /* Constructors */
PcfData();
public: /* Accessors: aggregates */
pcf_io_constraint_range io_constraints() const;
public: /* Public Accessors: Basic data query */
/* Get the pin to be constrained */
openfpga::BasicPort io_pin(const PcfIoConstraintId& io_id) const;
/* Get the net to be constrained */
std::string io_net(const PcfIoConstraintId& io_id) const;
/* Check if there are any io constraints */
bool empty() const;
/* Check if the data is valid: each pin can only be mapped to one net */
bool validate() const;
public: /* Public Mutators */
/* Reserve a number of design constraints to be memory efficent */
void reserve_io_constraints(const size_t& num_io_constraints);
/* Add a pin constraint to storage */
PcfIoConstraintId create_io_constraint();
/* Set the net for an io constraint */
void set_io_net(const PcfIoConstraintId& io_id,
const std::string& net);
/* Set the net for an io constraint */
void set_io_pin(const PcfIoConstraintId& io_id,
const std::string& pin);
public: /* Public invalidators/validators */
/* Show if the constraint id is a valid for data queries */
bool valid_io_constraint_id(const PcfIoConstraintId& io_id) const;
private: /* Internal data */
/* Unique ids for each design constraint */
vtr::vector<PcfIoConstraintId, PcfIoConstraintId> io_constraint_ids_;
/* Pins to constraint */
vtr::vector<PcfIoConstraintId, openfpga::BasicPort> io_constraint_pins_;
/* Nets to constraint */
vtr::vector<PcfIoConstraintId, std::string> io_constraint_nets_;
};
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,22 @@
/************************************************************************
* A header file for PinConstraints class, including critical data declaration
* Please include this file only for using any PinConstraints data structure
* Refer to pin_constraints.h for more details
***********************************************************************/
/************************************************************************
* Create strong id for PinConstraints to avoid illegal type casting
***********************************************************************/
#ifndef PCF_DATA_FWD_H
#define PCF_DATA_FWD_H
#include "vtr_strong_id.h"
struct pcf_io_constraint_id_tag;
typedef vtr::StrongId<pcf_io_constraint_id_tag> PcfIoConstraintId;
/* Short declaration of class */
class PcfData;
#endif

View File

@ -0,0 +1,72 @@
#include <cstdio>
#include <cassert>
#include "blif_head_reader.h"
namespace blifparse {
void BlifHeadReader::start_parse() {
//Pass
}
void BlifHeadReader::finish_parse() {
//Pass
}
void BlifHeadReader::begin_model(std::string model_name) {
// Pass
}
void BlifHeadReader::inputs(std::vector<std::string> input_conns) {
input_pins_ = input_conns;
}
void BlifHeadReader::outputs(std::vector<std::string> output_conns) {
output_pins_ = output_conns;
}
void BlifHeadReader::names(std::vector<std::string> nets, std::vector<std::vector<LogicValue>> so_cover) {
// Pass
}
void BlifHeadReader::latch(std::string input, std::string output, LatchType type, std::string control, LogicValue init) {
// Pass
}
void BlifHeadReader::subckt(std::string model, std::vector<std::string> ports, std::vector<std::string> nets) {
// Pass
}
void BlifHeadReader::blackbox() {
// Pass
}
void BlifHeadReader::end_model() {
// Pass
}
void BlifHeadReader::conn(std::string src, std::string dst) {
// Pass
}
void BlifHeadReader::cname(std::string cell_name) {
// Pass
}
void BlifHeadReader::attr(std::string name, std::string value) {
// Pass
}
void BlifHeadReader::param(std::string name, std::string value) {
// Pass
}
void BlifHeadReader::filename(std::string fname) {
// Pass
}
void BlifHeadReader::lineno(int line_num) {
// Pass
}
}

View File

@ -0,0 +1,54 @@
#ifndef BLIF_HEAD_READER
#define BLIF_HEAD_READER
#include <cstdio>
#include "blifparse.hpp"
#include "vtr_log.h"
namespace blifparse {
//An example callback which pretty-prints to stdout
//the BLIF which is being parsed
class BlifHeadReader : public Callback {
public:
void start_parse() override;
void filename(std::string fname) override;
void lineno(int line_num) override;
void begin_model(std::string model_name) override;
void inputs(std::vector<std::string> inputs) override;
void outputs(std::vector<std::string> outputs) override;
void names(std::vector<std::string> nets, std::vector<std::vector<LogicValue>> so_cover) override;
void latch(std::string input, std::string output, LatchType type, std::string control, LogicValue init) override;
void subckt(std::string model, std::vector<std::string> ports, std::vector<std::string> nets) override;
void blackbox() override;
void end_model() override;
//BLIF Extensions
void conn(std::string src, std::string dst) override;
void cname(std::string cell_name) override;
void attr(std::string name, std::string value) override;
void param(std::string name, std::string value) override;
void finish_parse() override;
void parse_error(const int curr_lineno, const std::string& near_text, const std::string& msg) override {
VTR_LOG_ERROR("Error when parsing .blif at line %d near '%s': %s\n", curr_lineno, near_text.c_str(), msg.c_str());
had_error_ = true;
}
bool had_error() { return had_error_; }
std::vector<std::string> input_pins() { return input_pins_; }
std::vector<std::string> output_pins() { return output_pins_; }
private:
std::vector<std::string> input_pins_;
std::vector<std::string> output_pins_;
bool had_error_ = false;
};
}
#endif

View File

@ -0,0 +1,78 @@
/******************************************************************************
* Inspired from https://github.com/genbtc/VerilogPCFparser
******************************************************************************/
#include <sstream>
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
#include "pcf_reader.h"
/* begin namespace openfpga */
namespace openfpga {
/**************************************************
* Constants
*************************************************/
constexpr char COMMENT = '#';
/********************************************************************
* A writer to output a repack pin constraint object to XML format
*
* Return 0 if successful
* Return 1 if there are serious errors when parsing data
* Return 2 if fail when opening files
*******************************************************************/
int read_pcf(const char* fname,
PcfData& pcf_data) {
vtr::ScopedStartFinishTimer timer("Read " + std::string(fname));
/* Create a file handler */
std::ifstream fp(fname);
if (!fp.is_open()) {
VTR_LOG_ERROR("Fail to open pcf file '%s'!", fname);
return 2;
}
int num_err = 0;
/* Get line by line */
std::string line;
while (std::getline(fp, line)) {
std::stringstream ss(line);
while (ss) {
std::string word;
/* TODO: Use command parser */
if (ss >> word) {
if (word.find("set_io") == 0) {
std::string net_name;
std::string pin_name;
ss >> net_name >> pin_name;
/* Decode data */
PcfIoConstraintId io_id = pcf_data.create_io_constraint();
pcf_data.set_io_net(io_id, net_name);
pcf_data.set_io_pin(io_id, pin_name);
} else if (word[0] == COMMENT) { // if it's a comment
break; //or ignore the full line comment and move on
} else {
/* Reach unknown command, error out */
VTR_LOG_ERROR("Unknown command '%s'!\n", word.c_str());
num_err++;
break; //and move onto next line. without this, it will accept more following values on this line
}
}
}
}
if (num_err) {
return 1;
}
return 0;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,21 @@
#ifndef PCF_READER_H
#define PCF_READER_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <stddef.h>
#include <array>
#include <map>
#include <fstream>
#include "pcf_data.h"
/* Begin namespace openfpga */
namespace openfpga {
/* Parse a .pcf file through a stream, return an object which contains all the data */
int read_pcf(const char* fname,
PcfData& pcf_data);
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,52 @@
/******************************************************************************
* Inspired from https://github.com/genbtc/VerilogPCFparser
******************************************************************************/
#include <sstream>
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
/* Headers from arch openfpga library */
#include "write_xml_utils.h"
#include "pcf_writer.h"
/* begin namespace openfpga */
namespace openfpga {
/**************************************************
* Constants
*************************************************/
constexpr char* CMD_SET_IO = "set_io";
/********************************************************************
* A writer to output a repack pin constraint object to XML format
*
* Return 0 if successful
* Return 1 if there are serious errors when parsing data
* Return 2 if fail when opening files
*******************************************************************/
int write_pcf(const char* fname,
const PcfData& pcf_data) {
vtr::ScopedStartFinishTimer timer("Write " + std::string(fname));
/* Create a file handler */
std::fstream fp;
/* Open the file stream */
fp.open(std::string(fname), std::fstream::out | std::fstream::trunc);
/* Write from data */
for (const PcfIoConstraintId& io_id : pcf_data.io_constraints()) {
fp << CMD_SET_IO << " ";
fp << pcf_data.io_net(io_id).c_str() << " ";
fp << generate_xml_port_name(pcf_data.io_pin(io_id)).c_str() << "\n";
}
return 0;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,21 @@
#ifndef PCF_WRITER_H
#define PCF_WRITER_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <stddef.h>
#include <array>
#include <map>
#include <fstream>
#include "pcf_data.h"
/* Begin namespace openfpga */
namespace openfpga {
/* Write a .pcf file from an object */
int write_pcf(const char* fname,
const PcfData& pcf_data);
} /* End namespace openfpga*/
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of pin constraints to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
#include "vtr_log.h"
/* Headers from libopenfpga util library */
#include "openfpga_port_parser.h"
#include "rapidcsv.h"
#include "read_csv_io_pin_table.h"
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Parse XML codes about <pin_constraints> to an object of PinConstraints
*******************************************************************/
IoPinTable read_csv_io_pin_table(const char* fname) {
vtr::ScopedStartFinishTimer timer("Read I/O Pin Table");
IoPinTable io_pin_table;
rapidcsv::Document doc(fname, rapidcsv::LabelParams(-1, -1),
rapidcsv::SeparatorParams(','));
/* TODO: Move this to constants */
std::map<std::string, e_side> side_str_map { {"TOP", TOP}, {"RIGHT", RIGHT}, {"LEFT", LEFT}, {"BOTTOM", BOTTOM} };
int num_rows = doc.GetRowCount();
io_pin_table.reserve_pins(num_rows);
for (int irow = 1; irow < num_rows; irow++) {
std::vector<std::string> row_vec = doc.GetRow<std::string>(irow);
IoPinTableId pin_id = io_pin_table.create_pin();
/* Fill pin-level information */
PortParser internal_pin_parser(row_vec.at(4));
io_pin_table.set_internal_pin(pin_id, internal_pin_parser.port());
PortParser external_pin_parser(row_vec.at(5));
io_pin_table.set_external_pin(pin_id, external_pin_parser.port());
std::string pin_side_str = row_vec.at(0);
if (side_str_map.end() == side_str_map.find(pin_side_str)) {
VTR_LOG("Invalid side defintion (='%s')! Expect [TOP|RIGHT|LEFT|BOTTOM]\n", pin_side_str.c_str());
exit(1);
} else {
io_pin_table.set_pin_side(pin_id, side_str_map[pin_side_str]);
}
/*This is not general purpose: we should have an explicit attribute in the csv file to decalare direction */
if (internal_pin_parser.port().get_name().find("A2F") != std::string::npos) {
io_pin_table.set_pin_direction(pin_id, IoPinTable::INPUT);
} else if (internal_pin_parser.port().get_name().find("F2A") != std::string::npos) {
io_pin_table.set_pin_direction(pin_id, IoPinTable::OUTPUT);
} else {
VTR_LOG("Invalid direction defintion! Expect [A2F|F2A] in the pin name\n");
exit(1);
}
}
return io_pin_table;
}
} /* End namespace openfpga*/

View File

@ -0,0 +1,20 @@
#ifndef READ_CSV_IO_PIN_TABLE_H
#define READ_CSV_IO_PIN_TABLE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "io_pin_table.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* Begin namespace openfpga */
namespace openfpga {
IoPinTable read_csv_io_pin_table(const char* fname);
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,93 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of I/O location to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from libopenfpga util library */
#include "openfpga_port_parser.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
#include "read_xml_io_location_map.h"
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Parse XML codes of a <set_io> to an object of PinConstraint
*******************************************************************/
static
void read_xml_one_io_location(pugi::xml_node& xml_io,
const pugiutil::loc_data& loc_data,
IoLocationMap& io_location_map) {
openfpga::PortParser port_parser(get_attribute(xml_io, "pad", loc_data).as_string());
int x_coord = get_attribute(xml_io, "x", loc_data).as_int();
int y_coord = get_attribute(xml_io, "y", loc_data).as_int();
int z_coord = get_attribute(xml_io, "z", loc_data).as_int();
/* Sanity checks */
if (x_coord < 0 || y_coord < 0 || z_coord < 0) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_io),
"Invalid coordinate (x, y, z) = (%d, %d, %d)! Expect zero or a positive integer!\n",
x_coord, y_coord, z_coord);
}
if (port_parser.port().get_width() != 1) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_io),
"I/O (%s) does not have a port size of 1!\n",
get_attribute(xml_io, "pad", loc_data).as_string());
}
io_location_map.set_io_index(size_t(x_coord), size_t(y_coord), size_t(z_coord), port_parser.port().get_name(), port_parser.port().get_lsb());
}
/********************************************************************
* Parse XML codes about <io_coordinates> to an object of PinConstraints
*******************************************************************/
IoLocationMap read_xml_io_location_map(const char* fname) {
vtr::ScopedStartFinishTimer timer("Read I/O Location Map");
IoLocationMap io_location_map;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, fname);
pugi::xml_node xml_root = get_single_child(doc, "io_coordinates", loc_data);
size_t num_children = std::distance(xml_root.children().begin(), xml_root.children().end());
/* TODO: Reserve memory space for efficiency */
for (pugi::xml_node xml_io : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_io.name() != std::string("io")) {
bad_tag(xml_io, loc_data, xml_root, {"io"});
}
read_xml_one_io_location(xml_io, loc_data, io_location_map);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(fname, e.line(),
"%s", e.what());
}
return io_location_map;
}
} /* End namespace openfpga*/

View File

@ -1,21 +1,20 @@
#ifndef OPENFPGA_CONSTRAIN_PIN_LOCATION_COMMAND_H
#define OPENFPGA_CONSTRAIN_PIN_LOCATION_COMMAND_H
#ifndef READ_XML_IO_LOCATION_MAP_H
#define READ_XML_IO_LOCATION_MAP_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "shell.h"
#include "openfpga_context.h"
#include "io_location_map.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
/* Begin namespace openfpga */
namespace openfpga {
void add_openfpga_constrain_pin_location_command(openfpga::Shell<OpenfpgaContext>& shell);
IoLocationMap read_xml_io_location_map(const char* fname);
} /* end namespace openfpga */
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,71 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of pin constraints to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
#include "vtr_log.h"
/* Headers from libopenfpga util library */
#include "openfpga_port_parser.h"
/* Headers from arch openfpga library */
#include "write_xml_utils.h"
#include "write_csv_io_pin_table.h"
/* Begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Write I/O pin table to a csv file
*
* Return 0 if successful
* Return 1 if there are more serious errors
* Return 2 if fail when creating files
*******************************************************************/
int write_csv_io_pin_table(const char* fname,
const IoPinTable& io_pin_table) {
vtr::ScopedStartFinishTimer timer("Write I/O Pin Table");
/* Create a file handler */
std::fstream fp;
/* Open the file stream */
fp.open(std::string(fname), std::fstream::out | std::fstream::trunc);
/* TODO: Move this to constants header file */
std::array<std::string, IoPinTable::NUM_IO_DIRECTIONS> IO_DIRECTION_STRING = {"input", "output"};
/* Print head row */
std::vector<std::string> head_row_str({"orientation", "port_name", "mapped_pin", "direction"});
for (size_t icol = 0; icol < head_row_str.size(); icol++) {
fp << head_row_str[icol];
if (icol < head_row_str.size() - 1) {
fp << ",";
}
}
fp << "\n";
/* Print data */
for (const IoPinTableId& pin_id : io_pin_table.pins()) {
std::vector<std::string> data_row_str;
data_row_str.push_back(SIDE_STRING[io_pin_table.pin_side(pin_id)]);
data_row_str.push_back(generate_xml_port_name(io_pin_table.internal_pin(pin_id)));
data_row_str.push_back(generate_xml_port_name(io_pin_table.external_pin(pin_id)));
data_row_str.push_back(IO_DIRECTION_STRING[io_pin_table.pin_direction(pin_id)]);
for (size_t icol = 0; icol < head_row_str.size(); icol++) {
fp << data_row_str[icol];
if (icol < data_row_str.size() - 1) {
fp << ",";
}
}
fp << "\n";
}
return 0;
}
} /* End namespace openfpga*/

View File

@ -0,0 +1,21 @@
#ifndef WRITE_CSV_IO_PIN_TABLE_H
#define WRITE_CSV_IO_PIN_TABLE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "io_pin_table.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* Begin namespace openfpga */
namespace openfpga {
int write_csv_io_pin_table(const char* fname,
const IoPinTable& io_pin_table);
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,42 @@
/********************************************************************
* 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 "blif_head_reader.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT(2 == argc);
/* Parse the blif */
blifparse::BlifHeadReader callback;
blifparse::blif_parse_filename(argv[1], callback);
VTR_LOG("Read the blif from a file: %s.\n",
argv[1]);
if (callback.had_error()) {
VTR_LOG("Read the blif ends with errors\n",
argv[1]);
return 1;
}
/* Output */
VTR_LOG("Input pins: \n");
for (const std::string& pin : callback.input_pins()) {
VTR_LOG("%s\n", pin.c_str());
}
VTR_LOG("Output pins: \n");
for (const std::string& pin : callback.output_pins()) {
VTR_LOG("%s\n", pin.c_str());
}
return 0;
}

View File

@ -0,0 +1,33 @@
/********************************************************************
* 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 "read_csv_io_pin_table.h"
#include "write_csv_io_pin_table.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT((2 == argc) || (3 == argc));
/* Parse the fabric key from an XML file */
openfpga::IoPinTable io_pin_table = openfpga::read_csv_io_pin_table(argv[1]);
VTR_LOG("Read the I/O pin table from a csv file: %s.\n",
argv[1]);
/* Output to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
write_csv_io_pin_table(argv[2], io_pin_table);
VTR_LOG("Echo the I/O pin table to a csv file: %s.\n",
argv[2]);
}
}

View File

@ -0,0 +1,34 @@
/********************************************************************
* 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 "pcf_reader.h"
#include "pcf_writer.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT((2 == argc) || (3 == argc));
/* Parse the fabric key from an XML file */
openfpga::PcfData pcf_data;
openfpga::read_pcf(argv[1], pcf_data);
VTR_LOG("Read the design constraints from a pcf file: %s.\n",
argv[1]);
/* Output to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
write_pcf(argv[2], pcf_data);
VTR_LOG("Echo the design constraints to a pcf file: %s.\n",
argv[2]);
}
}

View File

@ -0,0 +1,65 @@
/********************************************************************
* 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 "pcf_reader.h"
#include "blif_head_reader.h"
#include "read_csv_io_pin_table.h"
#include "read_xml_io_location_map.h"
#include "io_net_place.h"
#include "pcf2place.h"
int main(int argc, const char** argv) {
/* Ensure we have the following arguments:
* 1. Input - Users Design Constraints (.pcf)
* 2. Input - Netlist (.blif)
* 3. Input - Fabic I/O location map (.xml)
* 4. Input - Chip pin table (.csv)
* 5. Output - I/O placement (.place)
*/
VTR_ASSERT(6 == argc);
/* Parse the input files */
openfpga::PcfData pcf_data;
openfpga::read_pcf(argv[1], pcf_data);
VTR_LOG("Read the design constraints from a pcf file: %s.\n",
argv[1]);
blifparse::BlifHeadReader callback;
blifparse::blif_parse_filename(argv[2], callback);
VTR_LOG("Read the blif from a file: %s.\n",
argv[2]);
if (callback.had_error()) {
VTR_LOG("Read the blif ends with errors\n",
argv[2]);
return 1;
}
openfpga::IoLocationMap io_location_map = openfpga::read_xml_io_location_map(argv[3]);
VTR_LOG("Read the I/O location map from an XML file: %s.\n",
argv[3]);
openfpga::IoPinTable io_pin_table = openfpga::read_csv_io_pin_table(argv[4]);
VTR_LOG("Read the I/O pin table from a csv file: %s.\n",
argv[4]);
/* Convert */
openfpga::IoNetPlace io_net_place;
int status = pcf2place(pcf_data, callback.input_pins(), callback.output_pins(), io_pin_table, io_location_map, io_net_place);
if (status) {
return status;
}
/* Output */
status = io_net_place.write_to_place_file(argv[5], true, true);
return status;
}

View File

@ -0,0 +1,33 @@
/********************************************************************
* 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 "read_xml_io_location_map.h"
//#include "write_xml_io_location_map.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT((2 == argc) || (3 == argc));
/* Parse the fabric key from an XML file */
openfpga::IoLocationMap io_location_map = openfpga::read_xml_io_location_map(argv[1]);
VTR_LOG("Read the I/O location map from an XML file: %s.\n",
argv[1]);
/* Output to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
io_location_map.write_to_xml_file(std::string(argv[2]), true, true);
VTR_LOG("Echo the I/O location map to an XML file: %s.\n",
argv[2]);
}
}

View File

@ -1,40 +0,0 @@
cmake_minimum_required(VERSION 3.9)
project("libpinconstrain")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
file(GLOB_RECURSE BLIF_READ_HEADERS ../../vpr/src/base/*.h)
files_to_dirs(BLIF_READ_HEADERS BLIF_READ_INCLUDE_DIRS)
file(GLOB_RECURSE VTR_UTIL_HEADERS ../../libs/libvtrutil/src/*.h)
files_to_dirs(VTR_UTIL_HEADERS VTR_UTIL_INCLUDE_DIRS)
#Remove test executable from library
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES})
#Create the library
add_library(libpinconstrain STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(libpinconstrain PUBLIC ${LIB_INCLUDE_DIRS} ${BLIF_READ_INCLUDE_DIRS} ${VTR_UTIL_INCLUDE_DIRS})
set_target_properties(libpinconstrain PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Specify link-time dependancies
target_link_libraries(libpinconstrain
libvpr
libvtrutil
libpugixml)
#Create the test executable
foreach(testsourcefile ${EXEC_SOURCES})
# Use a simple string replace, to cut off .cpp.
get_filename_component(testname ${testsourcefile} NAME_WE)
add_executable(${testname} ${testsourcefile})
target_include_directories(${testname} PUBLIC ${LIB_INCLUDE_DIRS} ${BLIF_READ_INCLUDE_DIRS} ${VTR_UTIL_INCLUDE_DIRS})
# Make sure the library is linked to each test executable
target_link_libraries(${testname} libpinconstrain)
endforeach(testsourcefile ${EXEC_SOURCES})

View File

@ -1,3 +0,0 @@
set_io a pad_fpga_io[0]
set_io b pad_fpga_io[4]
set_io c pad_fpga_io[6]

View File

@ -1,17 +0,0 @@
orientation,row,col,pin_num_in_cell,port_name,mapped_pin,GPIO_type,Associated Clock,Clock Edge
TOP,,,,gfpga_pad_IO_A2F[0],pad_fpga_io[0],,,
TOP,,,,gfpga_pad_IO_F2A[0],pad_fpga_io[0],,,
TOP,,,,gfpga_pad_IO_A2F[4],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_F2A[4],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_A2F[8],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_F2A[8],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_A2F[31],pad_fpga_io[3],,,
TOP,,,,gfpga_pad_IO_F2A[31],pad_fpga_io[3],,,
RIGHT,,,,gfpga_pad_IO_A2F[32],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_F2A[32],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_A2F[40],pad_fpga_io[5],,,
RIGHT,,,,gfpga_pad_IO_F2A[40],pad_fpga_io[5],,,
BOTTOM,,,,gfpga_pad_IO_A2F[64],pad_fpga_io[6],,,
BOTTOM,,,,gfpga_pad_IO_F2A[64],pad_fpga_io[6],,,
LEFT,,,,gfpga_pad_IO_F2A[127],pad_fpga_io[7],,,
LEFT,,,,gfpga_pad_IO_A2F[127],pad_fpga_io[7],,,
1 orientation row col pin_num_in_cell port_name mapped_pin GPIO_type Associated Clock Clock Edge
2 TOP gfpga_pad_IO_A2F[0] pad_fpga_io[0]
3 TOP gfpga_pad_IO_F2A[0] pad_fpga_io[0]
4 TOP gfpga_pad_IO_A2F[4] pad_fpga_io[1]
5 TOP gfpga_pad_IO_F2A[4] pad_fpga_io[1]
6 TOP gfpga_pad_IO_A2F[8] pad_fpga_io[2]
7 TOP gfpga_pad_IO_F2A[8] pad_fpga_io[2]
8 TOP gfpga_pad_IO_A2F[31] pad_fpga_io[3]
9 TOP gfpga_pad_IO_F2A[31] pad_fpga_io[3]
10 RIGHT gfpga_pad_IO_A2F[32] pad_fpga_io[4]
11 RIGHT gfpga_pad_IO_F2A[32] pad_fpga_io[4]
12 RIGHT gfpga_pad_IO_A2F[40] pad_fpga_io[5]
13 RIGHT gfpga_pad_IO_F2A[40] pad_fpga_io[5]
14 BOTTOM gfpga_pad_IO_A2F[64] pad_fpga_io[6]
15 BOTTOM gfpga_pad_IO_F2A[64] pad_fpga_io[6]
16 LEFT gfpga_pad_IO_F2A[127] pad_fpga_io[7]
17 LEFT gfpga_pad_IO_A2F[127] pad_fpga_io[7]

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
XML file specification is primarily to define the mapping of the interface cell ports defined
in vpr_arch xml, to the EFPGA IO interface port names. This mapping is required by OpenFPGA
alongwith architecture definition file i.e. vpr_arch xml file. OpenFPGA will process this
file and use this information for IO placement and then later on use this to map it with the
user-defined pin-mapping file.
-->
<DEVICE name= "k4_N4_tileable_40nm" family="k4n4" width="6" height="6" z="8">
<IO>
<TOP_IO y="5">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[0:31]" startx="1" endx="4"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[0:31]" startx="1" endx="4"/>
</TOP_IO>
<RIGHT_IO x="5">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[32:63]" starty="4" endy="1"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[32:63]" starty="4" endy="1"/>
</RIGHT_IO>
<BOTTOM_IO y="0">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[64:95]" startx="4" endx="1"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[64:95]" startx="4" endx="1"/>
</BOTTOM_IO>
<LEFT_IO x="0">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[96:127]" starty="1" endy="4"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[96:127]" starty="1" endy="4"/>
</LEFT_IO>
</IO>
</DEVICE>

View File

@ -1,71 +0,0 @@
#include "vtr_path.h"
#include "read_blif.h"
#include "blifparse.hpp"
#include "blif_reader.h"
#include "vtr_log.h"
// blif parser callback
using namespace blifparse;
class BlifParserCallback : public Callback {
public:
void start_parse() override {}
void filename(std::string /*fname*/) override {}
void lineno(int /*line_num*/) override {}
void begin_model(std::string /*model_name*/) override {}
void inputs(std::vector<std::string> input_ports) override {
for (auto input_port : input_ports) {
inputs_.push_back(input_port);
}
}
void outputs(std::vector<std::string> output_ports) override {
for (auto output_port : output_ports) {
outputs_.push_back(output_port);
}
}
void names(std::vector<std::string> /*nets*/, std::vector<std:: vector<LogicValue>> /*so_cover*/) override {}
void latch(std::string /*input*/, std::string /*output*/, LatchType /* type*/, std::string /*control*/, LogicValue /*init*/) override {}
void subckt(std::string /*model*/, std::vector<std::string> /*ports*/, std:: vector<std::string> /*nets*/) override {}
void blackbox() override {}
void end_model() override {}
void finish_parse() override {}
void parse_error(const int curr_lineno, const std::string& near_text, const std::string& msg) override {
VTR_LOG_ERROR("Custom Error at line %d near '%s': %s\n", curr_lineno, near_text.c_str(), msg.c_str());
had_error_ = true;
}
bool had_error() { return had_error_ == true; }
std::vector<std::string> get_inputs() { return inputs_;}
std::vector<std::string> get_outputs() { return outputs_;}
private:
bool had_error_ = false;
std::vector<std::string> inputs_;
std::vector<std::string> outputs_;
};
// read port info from blif file
bool BlifReader::read_blif(const std::string &blif_file_name)
{
e_circuit_format circuit_format;
auto name_ext = vtr::split_ext(blif_file_name);
if (name_ext[1] == ".blif") {
circuit_format = e_circuit_format::BLIF;
} else if (name_ext[1] == ".eblif") {
circuit_format = e_circuit_format::EBLIF;
} else {
return false;
}
BlifParserCallback callback;
blif_parse_filename(blif_file_name, callback);
if (callback.had_error()) {
return false;
}
inputs = callback.get_inputs();
outputs = callback.get_outputs();
return true;
}

View File

@ -1,37 +0,0 @@
#ifndef BLIF_READER_H
#define BLIF_READER_H
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <map>
/*
Supported PCF commands:
* set_io <net> <pad> - constrain a given <net> to a given physical <pad> in eFPGA pinout.
* set_clk <pin> <net> - constrain a given global clock <pin> to a given <net>
Every tile where <net> is present will be constrained to use a given global clock.
*/
using namespace std;
class BlifReader
{
vector<string> inputs;
vector<string> outputs;
public:
BlifReader() {}
BlifReader(const std::string &f)
{
read_blif(f);
}
bool read_blif(const std::string &f);
const vector<string>& get_inputs()const { return inputs;}
const vector<string>& get_outputs()const { return outputs;}
};
#endif

View File

@ -1,53 +0,0 @@
#include "csv_reader.h"
#include <algorithm>
#include "vtr_log.h"
bool CvsReader::read_cvs(const std::string &f)
{
std::ifstream infile(f);
if (!infile.is_open())
{
VTR_LOG_ERROR("ERROR: cound not open the file %s.\n", f.c_str());
return false;
}
std::string line;
while (std::getline(infile, line))
{
// cout << line << " - " << endl;
if (!line.size())
continue;
entries.push_back(vector<string>());
entries.back().push_back(string(""));
for (auto c : line)
{
if (isspace(c))
continue;
if (c == ',')
{
entries.back().push_back(string(""));
}
else
entries.back().back().push_back(c);
}
}
std::vector<string> first_v = entries[0];
auto result1 = std::find(first_v.begin(), first_v.end(), "port_name");
vector<string>::iterator result2 = find(first_v.begin(), first_v.end(), "mapped_pin");
int port_name_index = distance(first_v.begin(), result1);
int mapped_pin_index = distance(first_v.begin(), result2);
for (auto &v : entries)
{
string port_name = v[port_name_index];
string mapped_pin = v[mapped_pin_index];
port_map.insert(std::pair<std::string, string>(mapped_pin, port_name));
//for (auto &s : v)
//{
// cout << s << " - ";
//}
}
return true;
}

View File

@ -1,26 +0,0 @@
#ifndef CVS_READER_H
#define CVS_READER_H
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <ctype.h>
#include <map>
using namespace std;
class CvsReader
{
vector<vector<string>> entries;
map<string, string> port_map;
public:
CvsReader() {}
bool read_cvs(const std::string &f);
const vector<vector<string>>& get_entries()const { return entries;}
const map<string, string>& get_port_map()const { return port_map;}
};
#endif

View File

@ -1,27 +0,0 @@
#include "pcf_reader.h"
#include "vtr_log.h"
bool PcfReader::read_pcf(const std::string &f)
{
std::ifstream infile(f);
if (!infile.is_open())
{
VTR_LOG_ERROR("ERROR: cound not open the file %s.\n", f.c_str());
return false;
}
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
std::string a, b, c;
if (!(iss >> a >> b >> c))
{
break;
} // error
commands.push_back(std::vector<std::string>());
commands.back().push_back(a);
commands.back().push_back(b);
commands.back().push_back(c);
}
return true;
}

View File

@ -1,34 +0,0 @@
#ifndef PCF_READER_H
#define PCF_READER_H
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <map>
/*
Supported PCF commands:
* set_io <net> <pad> - constrain a given <net> to a given physical <pad> in eFPGA pinout.
* set_clk <pin> <net> - constrain a given global clock <pin> to a given <net>
Every tile where <net> is present will be constrained to use a given global clock.
*/
class PcfReader
{
std::vector<std::vector<std::string>> commands;
public:
PcfReader() {}
PcfReader(const std::string &f)
{
read_pcf(f);
}
bool read_pcf(const std::string &f);
const std::vector<std::vector<std::string>>& get_commands()const { return commands;}
};
#endif

View File

@ -1,243 +0,0 @@
#include "xml_reader.h"
#include <vector>
#include <fstream>
//======================================================================
std::vector<std::string> XmlReader::vec_to_scalar(std::string str)
{
auto open_bracket_pos = str.find("[");
auto close_bracket_pos = str.find("]");
auto colon_pos = str.find(":");
std::vector<std::string> scalar_ports;
//Parse checks
if (open_bracket_pos == std::string::npos && close_bracket_pos != std::string::npos) {
//Close brace only
std::string msg = "near '" + str + "', missing '['";
std::cerr << " ERROR: " << msg << std::endl;
}
if (open_bracket_pos != std::string::npos && close_bracket_pos == std::string::npos) {
//Open brace only
std::string msg = "near '" + str + "', missing ']'";
std::cerr << " ERROR: " << msg << std::endl;
}
if (open_bracket_pos != std::string::npos && close_bracket_pos != std::string::npos) {
//Have open and close braces, close must be after open
if (open_bracket_pos > close_bracket_pos) {
std::string msg = "near '" + str + "', '[' after ']'";
std::cerr << " ERROR: " << msg << std::endl;
}
}
if (colon_pos != std::string::npos) {
//Have a colon, it must be between open/close braces
if (colon_pos > close_bracket_pos || colon_pos < open_bracket_pos) {
std::string msg = "near '" + str + "', found ':' but not between '[' and ']'";
std::cerr << " ERROR: " << msg << std::endl;
}
}
std::string name = str.substr(0, open_bracket_pos);
std::string first_idx_str;
std::string second_idx_str;
if (colon_pos == std::string::npos && open_bracket_pos == std::string::npos && close_bracket_pos == std::string::npos) {
} else if (colon_pos == std::string::npos) {
first_idx_str = str.substr(open_bracket_pos + 1, close_bracket_pos);
second_idx_str = first_idx_str;
} else {
first_idx_str = str.substr(open_bracket_pos + 1, colon_pos);
second_idx_str = str.substr(colon_pos + 1, close_bracket_pos);
}
int first_idx = std::stoi(first_idx_str);
int second_idx = std::stoi(second_idx_str);
if (first_idx < second_idx)
{
for(int i=first_idx; i < second_idx+1; i++)
{
std::string curr_port_name = name + '[' + std::to_string(i) + ']';
scalar_ports.push_back(curr_port_name);
}
}
else
{
for(int i=first_idx; i >= second_idx ; i--)
{
std::string curr_port_name = name + '[' + std::to_string(i) + ']';
scalar_ports.push_back(curr_port_name);
}
}
return scalar_ports;
}
//======================================================================
bool XmlReader::parse_io_cell (const pugi::xml_node xml_orient_io, const int row_or_col, const int io_per_cell, std::map<std::string, PinMappingData> *port_map)
{
pugi::xpath_node_set cells = xml_orient_io.select_nodes("CELL");
for (pugi::xpath_node_set::const_iterator it = cells.begin(); it != cells.end(); ++it)
{
pugi::xpath_node node = *it;
int startx, starty, endx, endy, i, j, x, y;
std::string port_name = node.node().attribute("port_name").as_string();
std::string mapped_name = node.node().attribute("mapped_name").as_string();
std::vector<std::string> scalar_mapped_pins = vec_to_scalar(mapped_name);
i = 0;
if (node.node().attribute("startx") && node.node().attribute("endx"))
{
startx = node.node().attribute("startx").as_int();
endx = node.node().attribute("endx").as_int();
y = row_or_col;
if (startx < endx)
{
for (x=startx; x < endx+1; x++)
{
for (j=0; j < io_per_cell; j++)
{
std::string mapped_pin = scalar_mapped_pins[i];
PinMappingData pinMapData = PinMappingData(port_name, mapped_pin, x, y, j);
port_map->insert(std::pair<std::string, PinMappingData>(mapped_pin, pinMapData));
i++;
}
}
}
else
{
for (x=startx; x >= endx; x--)
{
for (j=0; j < io_per_cell; j++)
{
std::string mapped_pin = scalar_mapped_pins[i];
PinMappingData pinMapData = PinMappingData(port_name, mapped_pin, x, y, j);
port_map->insert(std::pair<std::string, PinMappingData>(mapped_pin, pinMapData));
i++;
}
}
}
}
if (node.node().attribute("starty") && node.node().attribute("endy").value())
{
starty = node.node().attribute("starty").as_int();
endy = node.node().attribute("endy").as_int();
x = row_or_col;
if (starty < endy)
{
for (y=starty; y < endy+1; y++)
{
for (j=0; j < io_per_cell; j++)
{
std::string mapped_pin = scalar_mapped_pins[i];
PinMappingData pinMapData = PinMappingData(port_name, mapped_pin, x, y, j);
port_map->insert(std::pair<std::string, PinMappingData>(mapped_pin, pinMapData));
i++;
}
}
}
else
{
for (y=starty; y >= endy; y--)
{
for (j=0; j < io_per_cell; j++)
{
std::string mapped_pin = scalar_mapped_pins[i];
PinMappingData pinMapData = PinMappingData(port_name, mapped_pin, x, y, j);
port_map->insert(std::pair<std::string, PinMappingData>(mapped_pin, pinMapData));
i++;
}
}
}
}
}
return true;
}
//======================================================================
bool XmlReader::parse_io (const pugi::xml_node xml_io, const int width, const int height, const int io_per_cell, std::map<std::string, PinMappingData> *port_map)
{
pugi::xml_node xml_top_io = xml_io.child("TOP_IO");
if (!xml_top_io)
{
return false;
}
int io_row_top = height - 1;
if (xml_top_io.attribute("y"))
io_row_top = xml_top_io.attribute("y").as_int();
pugi::xml_node xml_bottom_io = xml_io.child("BOTTOM_IO");
if (!xml_bottom_io)
{
return false;
}
int io_row_bottom = 0;
if (xml_bottom_io.attribute("y"))
io_row_bottom = xml_bottom_io.attribute("y").as_int();
pugi::xml_node xml_left_io = xml_io.child("LEFT_IO");
if (!xml_left_io)
{
return false;
}
int io_col_left = 0;
if (xml_left_io.attribute("x"))
io_col_left = xml_left_io.attribute("x").as_int();
pugi::xml_node xml_right_io = xml_io.child("RIGHT_IO");
if (!xml_right_io)
{
return false;
}
int io_col_right = width - 1;
if (xml_right_io.attribute("x"))
io_col_right = xml_right_io.attribute("x").as_int();
if (!parse_io_cell (xml_top_io, io_row_top, io_per_cell, port_map))
return false;
if (!parse_io_cell (xml_bottom_io, io_row_bottom, io_per_cell, port_map))
return false;
if (!parse_io_cell (xml_right_io, io_col_right, io_per_cell, port_map))
return false;
if (!parse_io_cell (xml_left_io, io_col_left, io_per_cell, port_map))
return false;
return true;
}
//======================================================================
bool XmlReader::read_xml(const std::string &f)
{
pugi::xml_document doc;
std::ifstream infile(f);
if (!infile.is_open())
{
std::cerr << "ERROR: cound not open the file " << f << std::endl;
return false;
}
pugi::xml_parse_result result = doc.load_file(f.c_str());
if (!result)
return false;
pugi::xml_node device = doc.child("DEVICE");
if (!device)
return false;
int width = device.attribute("width").as_int();
int height = device.attribute("height").as_int();
int z = device.attribute("z").as_int();
if (z <= 0)
return false;
pugi::xml_node xml_io = device.child("IO");
if (!xml_io)
return false;
if (!parse_io (xml_io, width, height, z, &port_map_))
return false;
return true;
}

View File

@ -1,41 +0,0 @@
#ifndef XML_READER_H
#define XML_READER_H
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include "pugixml.hpp"
class PinMappingData
{
public:
PinMappingData(std::string p_name, std::string map_pin, int x, int y, int z):port_name_(p_name), mapped_pin_(map_pin), x_(x), y_(y), z_(z){}
std::string get_port_name () { return port_name_; }
std::string get_mapped_pin () { return mapped_pin_; }
int get_x () { return x_; }
int get_y () { return y_; }
int get_z () { return z_; }
private:
std::string port_name_;
std::string mapped_pin_;
int x_;
int y_;
int z_;
};
class XmlReader
{
std::map<std::string, PinMappingData> port_map_;
public:
XmlReader() {}
bool read_xml(const std::string &f);
const std::map<std::string, PinMappingData>& get_port_map()const { return port_map_;}
std::vector<std::string> vec_to_scalar(std::string str);
bool parse_io_cell (const pugi::xml_node xml_orient_io, const int row_or_col, const int io_per_cell, std::map<std::string, PinMappingData> *port_map);
bool parse_io (const pugi::xml_node xml_io, const int width, const int height, const int io_per_cell, std::map<std::string, PinMappingData> *port_map);
};
#endif

View File

@ -1,23 +0,0 @@
#include <iostream>
#include <string>
#include "csv_reader.h"
#include "pcf_reader.h"
#include "xml_reader.h"
#include "cmd_line.h"
// #include "pin_location.h"
#include "pin_constrain_loc.h"
// Convert a PCF file into a VPR io.place file.
// This requires : XML file where we can get (x, y, z) of internal port
// CSV file where we have the maching list (external, internal) ports
// PCF file: constraint file. a design pin can be assigned to an external port
// BLIF file: user design. We need to check the input and output. Special handling for outputs
// The output is a file constraint in VPR format.
// Usage options: --xml PINMAP_XML --pcf PCF --blif BLIF --output OUTPUT --xml PINMAP_XML --csv CSV_FILE
int main(int argc, const char* argv[])
{
cmd_line cmd(argc, argv);
return pin_constrain_location_cmd_line(cmd);
}

View File

@ -1,30 +0,0 @@
#include "pin_location.h"
#include "cmd_line.h"
#include "pin_constrain_loc.h"
#include <vector>
#include <string>
// wraper function to do the real job, it is used by openfpga shell as well
// this gurantees same behavior
int pin_constrain_location (vector<string> args) {
if (args.size() != PIN_C_ARGUMENT_NUMBER ) {
return 1;
}
const char* pin_c_args [PIN_C_ARGUMENT_NUMBER];
for (int i = 0; i < PIN_C_ARGUMENT_NUMBER; i++) {
pin_c_args[i] = const_cast<char*> (args[i].c_str());
}
cmd_line pin_c_cmd (PIN_C_ARGUMENT_NUMBER, pin_c_args);
return pin_constrain_location_cmd_line(pin_c_cmd);
}
// base function for both openfpga wrapper and pin_c executable
int pin_constrain_location_cmd_line (cmd_line& cmd) {
pin_location pl (cmd);
//pl.get_cmd().print_options();
if (!pl.reader_and_writer()) {
return 1;
}
return 0;
}

View File

@ -1,12 +0,0 @@
#include "pin_location.h"
#include "cmd_line.h"
#include <vector>
#include <string>
// wraper function to do the real job, it is used by openfpga shell as well
// this gurantees same behavior
int pin_constrain_location (std::vector<std::string> args);
// base function for both openfpga wrapper and pin_c executable
int pin_constrain_location_cmd_line (cmd_line& cmd);

View File

@ -1,141 +0,0 @@
#include "csv_reader.h"
#include "pcf_reader.h"
#include "xml_reader.h"
#include "blif_reader.h"
#include "cmd_line.h"
#include "pin_location.h"
#include <algorithm>
#include <set>
#include "vtr_log.h"
const string USAGE_MSG = "usage options: --xml PINMAP_XML --pcf PCF --blif BLIF --csv CSV_FILE --output OUTPUT";
const cmd_line & pin_location::get_cmd() const
{
return cl_;
}
bool pin_location::reader_and_writer()
{
cmd_line cmd = cl_;
string xml_name = cmd.get_param("--xml");
string csv_name = cmd.get_param("--csv");
string pcf_name = cmd.get_param("--pcf");
string blif_name = cmd.get_param("--blif");
string output_name = cmd.get_param("--output");
if ((xml_name == "") || (csv_name == "") || (pcf_name == "") || (blif_name == "")|| (output_name == "") )
{
VTR_LOG_ERROR("%s\n %s\n", error_messages[MISSING_IN_OUT_FILES].c_str(), USAGE_MSG.c_str());
return false;
}
XmlReader rd_xml;
if (!rd_xml.read_xml(xml_name))
{
VTR_LOG_ERROR("%s.\n", error_messages[PIN_LOC_XML_PARSE_ERROR].c_str());
return false;
}
std::map<std::string, PinMappingData> xml_port_map = rd_xml.get_port_map();
CvsReader rd_csv;
if (!rd_csv.read_cvs(csv_name))
{
VTR_LOG_ERROR("%s.\n", error_messages[PIN_MAP_CSV_PARSE_ERROR].c_str());
return false;
}
map<string, string> csv_port_map = rd_csv.get_port_map();
PcfReader rd_pcf;
if (!rd_pcf.read_pcf(pcf_name))
{
VTR_LOG_ERROR("%s.\n", error_messages[PIN_CONSTRAINT_PARSE_ERROR].c_str());
return false;
}
// read port info from blif file
BlifReader rd_blif;
if (!rd_blif.read_blif(blif_name)) {
VTR_LOG_ERROR("%s.\n", error_messages[INPUT_DESIGN_PARSE_ERROR].c_str());
return false;
}
std::vector<std::string> inputs = rd_blif.get_inputs();
std::vector<std::string> outputs = rd_blif.get_outputs();
std::ofstream out_file;
out_file.open(output_name);
out_file << "#Block Name x y z\n";
out_file << "#------------ -- -- -\n";
vector<vector<string>> pcf_pin_cstr = rd_pcf.get_commands();
std::set<std::string> constrained_ports, constrained_pins;
for (auto pin_cstr_v : pcf_pin_cstr)
{
if ((pin_cstr_v[0] != "set_io") && (pin_cstr_v[0] != "set_clk"))
continue;
string pin_name = pin_cstr_v[1];
string cstr_name = pin_cstr_v[2];
auto found_in = std::find(inputs.begin(), inputs.end(), pin_name);
bool valid = false, is_out = false;
if (found_in != inputs.end())
valid = true;
else
{
auto found_out = std::find(outputs.begin(), outputs.end(), pin_name);
if (found_out != outputs.end())
{
valid = true;
is_out = true;
}
else
{
VTR_LOG_ERROR("%s: <%s>.\n", error_messages[CONSTRAINED_PORT_NOT_FOUND].c_str(), pin_name.c_str());
out_file.close();
return false;
}
}
if (constrained_ports.find(pin_name) == constrained_ports.end()) {
constrained_ports.insert(pin_name);
} else {
VTR_LOG_ERROR("%s: <%s>.\n", error_messages[RE_CONSTRAINED_PORT].c_str(), pin_name.c_str());
out_file.close();
return false;
}
if (!valid)
continue;
std::string content_to_write;
// Get the the intternal port from the CSV file
auto element_cstr = csv_port_map.find(cstr_name);
if (element_cstr != csv_port_map.end())
{
if (constrained_pins.find(cstr_name) == constrained_pins.end()) {
constrained_pins.insert(cstr_name);
} else {
VTR_LOG_ERROR("%s: <%s>.\n", error_messages[OVERLAP_PIN_IN_CONSTRAINT].c_str(), cstr_name.c_str());
out_file.close();
return false;
}
// Get the (x, y, z) from the XML reader
PinMappingData pinMapData = xml_port_map.at(element_cstr->second);
if (is_out)
{
content_to_write += "out:";
}
content_to_write += pin_name + " " + std::to_string(pinMapData.get_x()) + " " + std::to_string(pinMapData.get_y()) + " " + std::to_string(pinMapData.get_z()) + "\n";
} else {
VTR_LOG_ERROR("%s: <%s>.\n", error_messages[CONSTRAINED_PIN_NOT_FOUND].c_str(), cstr_name.c_str());
out_file.close();
return false;
}
out_file << content_to_write;
}
out_file.close();
return true;
}

View File

@ -1,46 +0,0 @@
#ifndef PIN_LOCATION_H
#define PIN_LOCATION_H
#include "cmd_line.h"
// number of arguments for "pin_c", inlcuding the "pin_c" command itself
#define PIN_C_ARGUMENT_NUMBER 11
class pin_location {
private:
// error messages to be printed out with std::cerr
enum {
MISSING_IN_OUT_FILES = 0,
PIN_LOC_XML_PARSE_ERROR,
PIN_MAP_CSV_PARSE_ERROR,
PIN_CONSTRAINT_PARSE_ERROR,
INPUT_DESIGN_PARSE_ERROR,
CONSTRAINED_PORT_NOT_FOUND,
CONSTRAINED_PIN_NOT_FOUND,
RE_CONSTRAINED_PORT,
OVERLAP_PIN_IN_CONSTRAINT,
MAX_MESSAGE_ID
};
std::string error_messages[MAX_MESSAGE_ID] = {
"Missing input or output file arguments", // MISSING_IN_OUT_FILES
"Pin location file parse error", // PIN_LOC_XML_PARSE_ERROR
"Pin map file parse error", // PIN_MAP_CSV_PARSE_ERROR
"Pin constraint file parse error", // PIN_CONSTRAINT_PARSE_ERROR
"Input design parse error", // INPUT_DESIGN_PARSE_ERROR
"Constrained port not found in design", // CONSTRAINED_PORT_NOT_FOUND
"Constrained pin not found in device", // CONSTRAINED_PIN_NOT_FOUND
"Re-constrained port", // RE_CONSTRAINED_PORT
"Overlap pin found in constraint" // OVERLAP_PIN_IN_CONSTRAINT
};
cmd_line cl_;
public:
pin_location(cmd_line& cl): cl_(cl){
}
const cmd_line& get_cmd()const;
bool reader_and_writer();
};
#endif

View File

@ -1,77 +0,0 @@
#include "cmd_line.h"
cmd_line::cmd_line(int argc, const char *argv[])
{
bool needVal = false;
string key;
for (int i = 1; i < argc; ++i)
{
string s(argv[i]);
if (s.size() < 2)
{
cout << "Warning: Not a valid flag \"" << s << "\" discarding" << endl;
continue;
}
if ('-' == s[0])
{
if ('-' == s[1])
{ // param key
if (needVal)
cout << "Warning: Key " << key << " did not get a value" << endl;
needVal = true;
key = s;
}
else
{ // flag
flags.insert(s);
if (needVal)
cout << "Warning: Key " << key << " did not get a value" << endl;
needVal = false;
}
}
else
{ // param value
if (needVal)
{
params[key] = s;
needVal = false;
}
else
{
cout << "Warning: No key for value " << s << endl;
}
}
}
}
bool cmd_line::is_flag_set(string &fl)
{
return (flags.find(fl) != end(flags));
}
string cmd_line::get_param(const string &key)
{
if (params.find(key) != end(params))
return params[key];
return "";
}
void cmd_line::set_flag(string &fl)
{
flags.insert(fl);
}
void cmd_line::set_param_value(string &key, string &val)
{
params[key] = val;
}
void cmd_line::print_options() const
{
cout << "Flags :\n";
for (auto &f : flags)
cout << "\t" << f << endl;
cout << "Params :\n";
for (auto &p : params)
cout << "\t" << p.first << "\t" << p.second << endl;
}

View File

@ -1,23 +0,0 @@
#ifndef CMD_LINE
#define CMD_LINE
#include <iostream>
#include <unordered_map>
#include <unordered_set>
using namespace std;
class cmd_line
{
unordered_map<string, string> params;
unordered_set<string> flags;
public:
cmd_line(int argc, const char *argv[]);
const unordered_set<string> &get_flag_set() const { return flags; }
const unordered_map<string, string> get_param_map() const { return params; }
bool is_flag_set(string &fl);
string get_param(const string &key);
void set_flag(string &fl);
void set_param_value(string &key, string &val);
void print_options() const;
};
#endif

View File

@ -1,30 +0,0 @@
/********************************************************************
* 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"
#include "cmd_line.h"
#include "pin_location.h"
#include "pin_constrain_loc.h"
int main(int argc, const char** argv) {
VTR_ASSERT(argc == PIN_C_ARGUMENT_NUMBER);
string command_line;
for (int i = 0; i < argc; i++) {
if (i > 0) {
command_line += " ";
}
command_line += argv[i];
}
VTR_LOG("Created command line <%s> for test.\n", command_line.c_str());
cmd_line pin_c_cmd (argc, argv);
VTR_LOG("Testing reader and writer.\n");
int status = pin_constrain_location_cmd_line(pin_c_cmd);
VTR_LOG("Test result: %s.\n", status == 0 ? "PASS" : "FAIL");
return status;
}

View File

@ -1,3 +0,0 @@
set_io a pad_fpga_io[0]
set_io b pad_fpga_io[4]
set_io c pad_fpga_io[6]

View File

@ -1,35 +0,0 @@
cmake_minimum_required(VERSION 3.9)
project("librepackdc")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Remove test executable from library
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES})
#Create the library
add_library(librepackdc STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(librepackdc PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(librepackdc PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Specify link-time dependancies
target_link_libraries(librepackdc
libopenfpgautil
libarchopenfpga
libvtrutil
libpugixml
libpugiutil)
#Create the test executable
foreach(testsourcefile ${EXEC_SOURCES})
# Use a simple string replace, to cut off .cpp.
get_filename_component(testname ${testsourcefile} NAME_WE)
add_executable(${testname} ${testsourcefile})
# Make sure the library is linked to each test executable
target_link_libraries(${testname} librepackdc)
endforeach(testsourcefile ${EXEC_SOURCES})

View File

@ -23,14 +23,12 @@ target_link_libraries(libopenfpga
libopenfpgashell
libopenfpgautil
libfabrickey
librepackdc
libfpgabitstream
libini
libpcf
libvtrutil
libbusgroup
libvpr
libpinconstrain)
libvpr)
#Create the test executable
add_executable(openfpga ${EXEC_SOURCE})

View File

@ -1,96 +0,0 @@
/********************************************************************
* This file includes functions to build bitstream database
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_time.h"
#include "vtr_log.h"
/* Headers from openfpgashell library */
#include "command_exit_codes.h"
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
#include "openfpga_reserved_words.h"
#include "openfpga_naming.h"
#include "openfpga_constrain_pin_location.h"
/* Include global variables of VPR */
#include "globals.h"
/* begin namespace openfpga */
extern int pin_constrain_location (std::vector<std::string> args);
namespace openfpga {
/********************************************************************
* Top-level function to read an OpenFPGA architecture file
* we use the APIs from the libarchopenfpga library
*
* The command will accept an option '--file' which is the architecture
* file provided by users
*******************************************************************/
int constrain_pin_location(OpenfpgaContext& openfpga_context, const Command& cmd, const CommandContext& cmd_context) {
/* initialize arguments with sanity check*/
std::vector<std::string> pin_constrain_args;
pin_constrain_args.push_back("pin_c");
/* todo: create a factory to produce this in the future*/
std::string pcf_option_name = "pcf";
CommandOptionId opt_pcf_file = cmd.option(pcf_option_name);
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_pcf_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_pcf_file).empty());
std::string pcf_file_name = cmd_context.option_value(cmd, opt_pcf_file);
pin_constrain_args.push_back(std::string("--") + pcf_option_name);
pin_constrain_args.push_back(pcf_file_name.c_str());
std::string blif_option_name = "blif";
CommandOptionId opt_blif_file = cmd.option(blif_option_name);
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_blif_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_blif_file).empty());
std::string blif_file_name = cmd_context.option_value(cmd, opt_blif_file);
pin_constrain_args.push_back(std::string("--") + blif_option_name);
pin_constrain_args.push_back(blif_file_name);
#if 0
// --net is not supported by pin_c yet
std::string net_option_name = "net";
CommandOptionId opt_net_file = cmd.option(net_option_name);
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_net_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_net_file).empty());
std::string net_file_name = cmd_context.option_value(cmd, opt_net_file);
pin_constrain_args.push_back(std::string("--") + net_option_name);
pin_constrain_args.push_back(net_file_name);
#endif
std::string pinmap_xml_option_name = "pinmap_xml";
CommandOptionId opt_pinmap_xml_file = cmd.option(pinmap_xml_option_name);
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_pinmap_xml_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_pinmap_xml_file).empty());
std::string pinmap_xml_file_name = cmd_context.option_value(cmd, opt_pinmap_xml_file);
pin_constrain_args.push_back(std::string("--xml"));
pin_constrain_args.push_back(pinmap_xml_file_name);
std::string csv_file_option_name = "csv_file";
CommandOptionId opt_csv_file = cmd.option(csv_file_option_name);
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_csv_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_csv_file).empty());
std::string csv_file_name = cmd_context.option_value(cmd, opt_csv_file);
pin_constrain_args.push_back(std::string("--csv"));
pin_constrain_args.push_back(csv_file_name);
std::string output_option_name = "output";
CommandOptionId opt_output_file = cmd.option(output_option_name);
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_output_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_output_file).empty());
std::string output_file_name = cmd_context.option_value(cmd, opt_output_file);
pin_constrain_args.push_back(std::string("--") + output_option_name);
pin_constrain_args.push_back(output_file_name);
if (pin_constrain_location(pin_constrain_args)) {
return CMD_EXEC_FATAL_ERROR;
}
return CMD_EXEC_SUCCESS;
}
} /* end namespace openfpga */

View File

@ -1,49 +0,0 @@
/********************************************************************
* Add commands to the OpenFPGA shell interface,
* in purpose of setting up OpenFPGA core engine, including:
* - read_openfpga_arch : read OpenFPGA architecture file
*******************************************************************/
#include "openfpga_constrain_pin_location_command.h"
#include "openfpga_constrain_pin_location.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* - Add a command to Shell environment: constrain_pin_location
* - Add associated options
* - Add command dependency
*******************************************************************/
void add_openfpga_constrain_pin_location_command(openfpga::Shell<OpenfpgaContext>& shell) {
Command shell_cmd("constrain_pin_location");
/* Options are created by following the python script crafted by QL, since that has been used for a while:
python3 create_ioplace.py --pcf pcf_file --blif blif_file --net net_file --pinmap_xml pinmap_xml_file --csv_file csv_file --output outputplace_file
*/
/* Add an option '--pcf'*/
CommandOptionId opt_pcf_file = shell_cmd.add_option("pcf", true, "file path to the user pin constraint");
shell_cmd.set_option_require_value(opt_pcf_file, openfpga::OPT_STRING);
/* Add an option '--blif'*/
CommandOptionId opt_blif_file = shell_cmd.add_option("blif", true, "file path to the synthesized blif");
shell_cmd.set_option_require_value(opt_blif_file, openfpga::OPT_STRING);
/* Add an option '--pinmap_xml'*/
CommandOptionId opt_pinmap_file = shell_cmd.add_option("pinmap_xml", true, "file path to the pin location XML");
shell_cmd.set_option_require_value(opt_pinmap_file, openfpga::OPT_STRING);
/* Add an option '--csv_file'*/
CommandOptionId opt_csv_file = shell_cmd.add_option("csv_file", true, "file path to the pin map csv");
shell_cmd.set_option_require_value(opt_csv_file, openfpga::OPT_STRING);
/* Add an option '--output'*/
CommandOptionId opt_output_file = shell_cmd.add_option("output", true, "file path to the output");
shell_cmd.set_option_require_value(opt_output_file, openfpga::OPT_STRING);
/* Add command 'constrain_pin_location' to the Shell */
ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "constrain pin location by generating a place file");
shell.set_command_execute_function(shell_cmd_id, constrain_pin_location);
}
} /* end namespace openfpga */

View File

@ -0,0 +1,90 @@
/********************************************************************
* This file includes functions to build bitstream database
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_time.h"
#include "vtr_log.h"
/* Headers from openfpgashell library */
#include "command_exit_codes.h"
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
/* Headers from pcf library */
#include "pcf_reader.h"
#include "blif_head_reader.h"
#include "read_csv_io_pin_table.h"
#include "read_xml_io_location_map.h"
#include "io_net_place.h"
#include "pcf2place.h"
#include "openfpga_pcf2place.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Top-level function to convert a .pcf file to a .place file which
* which VPR can force I/O placement
*******************************************************************/
int pcf2place_wrapper(const OpenfpgaContext& openfpga_context,
const Command& cmd, const CommandContext& cmd_context) {
/* todo: create a factory to produce this in the future*/
CommandOptionId opt_pcf = cmd.option("pcf");
CommandOptionId opt_blif = cmd.option("blif");
CommandOptionId opt_fpga_io_map = cmd.option("fpga_io_map");
CommandOptionId opt_pin_table = cmd.option("pin_table");
CommandOptionId opt_fpga_fix_pins = cmd.option("fpga_fix_pins");
CommandOptionId opt_no_time_stamp = cmd.option("no_time_stamp");
CommandOptionId opt_verbose = cmd.option("verbose");
std::string pcf_fname = cmd_context.option_value(cmd, opt_pcf);
std::string blif_fname = cmd_context.option_value(cmd, opt_blif);
std::string fpga_io_map_fname = cmd_context.option_value(cmd, opt_fpga_io_map);
std::string pin_table_fname = cmd_context.option_value(cmd, opt_pin_table);
std::string fpga_fix_pins_fname = cmd_context.option_value(cmd, opt_fpga_fix_pins);
/* Parse the input files */
openfpga::PcfData pcf_data;
openfpga::read_pcf(pcf_fname.c_str(), pcf_data);
VTR_LOG("Read the design constraints from a pcf file: %s.\n",
pcf_fname.c_str());
blifparse::BlifHeadReader callback;
blifparse::blif_parse_filename(blif_fname.c_str(), callback);
VTR_LOG("Read the blif from a file: %s.\n",
blif_fname.c_str());
if (callback.had_error()) {
VTR_LOG_ERROR("Read the blif ends with errors\n");
return CMD_EXEC_FATAL_ERROR;
}
IoLocationMap io_location_map = read_xml_io_location_map(fpga_io_map_fname.c_str());
VTR_LOG("Read the I/O location map from an XML file: %s.\n",
fpga_io_map_fname.c_str());
IoPinTable io_pin_table = read_csv_io_pin_table(pin_table_fname.c_str());
VTR_LOG("Read the I/O pin table from a csv file: %s.\n",
pin_table_fname.c_str());
/* Convert */
IoNetPlace io_net_place;
int status = pcf2place(pcf_data, callback.input_pins(), callback.output_pins(), io_pin_table, io_location_map, io_net_place);
if (status) {
return status;
}
/* Output */
status = io_net_place.write_to_place_file(fpga_fix_pins_fname.c_str(),
cmd_context.option_enable(cmd, opt_no_time_stamp),
cmd_context.option_enable(cmd, opt_verbose));
if (status) {
return status;
}
return CMD_EXEC_SUCCESS;
}
} /* end namespace openfpga */

View File

@ -1,5 +1,5 @@
#ifndef OPENFPGA_BITSTREAM_H
#define OPENFPGA_BITSTREAM_H
#ifndef OPENFPGA_PCF2PLACE_H
#define OPENFPGA_PCF2PLACE_H
/********************************************************************
* Include header files that are required by function declaration
@ -14,7 +14,10 @@
/* begin namespace openfpga */
namespace openfpga {
int constrain_pin_location(OpenfpgaContext& openfpga_context, const Command& cmd, const CommandContext& cmd_context);
int pcf2place_wrapper(const OpenfpgaContext& openfpga_context,
const Command& cmd, const CommandContext& cmd_context);
} /* end namespace openfpga */
#endif

View File

@ -10,6 +10,7 @@
#include "check_netlist_naming_conflict.h"
#include "openfpga_build_fabric.h"
#include "openfpga_write_gsb.h"
#include "openfpga_pcf2place.h"
#include "openfpga_setup_command.h"
/* begin namespace openfpga */
@ -421,6 +422,50 @@ ShellCommandId add_openfpga_write_fabric_io_info_command(openfpga::Shell<Openfpg
return shell_cmd_id;
}
/********************************************************************
* - Add a command to Shell environment: pcf2place
* - Add associated options
* - Add command dependency
*******************************************************************/
static
ShellCommandId add_openfpga_pcf2place_command(openfpga::Shell<OpenfpgaContext>& shell,
const ShellCommandClassId& cmd_class_id) {
Command shell_cmd("pcf2place");
/* Add an option '--pcf'*/
CommandOptionId opt_pcf_file = shell_cmd.add_option("pcf", true, "file path to the user pin constraint");
shell_cmd.set_option_require_value(opt_pcf_file, openfpga::OPT_STRING);
/* Add an option '--blif'*/
CommandOptionId opt_blif_file = shell_cmd.add_option("blif", true, "file path to the synthesized netlist (.blif)");
shell_cmd.set_option_require_value(opt_blif_file, openfpga::OPT_STRING);
/* Add an option '--fpga_io_map'*/
CommandOptionId opt_fpga_io_map_file = shell_cmd.add_option("fpga_io_map", true, "file path to FPGA I/O location map (.xml)");
shell_cmd.set_option_require_value(opt_fpga_io_map_file, openfpga::OPT_STRING);
/* Add an option '--pin_table'*/
CommandOptionId opt_pin_table_file = shell_cmd.add_option("pin_table", true, "file path to the pin table (.csv)");
shell_cmd.set_option_require_value(opt_pin_table_file, openfpga::OPT_STRING);
/* Add an option '--fpga_fix_pins'*/
CommandOptionId opt_fpga_fix_pins_file = shell_cmd.add_option("fpga_fix_pins", true, "file path to the output fix-pin placement file (.place)");
shell_cmd.set_option_require_value(opt_fpga_fix_pins_file, openfpga::OPT_STRING);
/* Add an option '--no_time_stamp' */
shell_cmd.add_option("no_time_stamp", false, "Do not print time stamp in output files");
/* Add an option '--verbose' */
shell_cmd.add_option("verbose", false, "Enable verbose output");
/* Add command to the Shell */
ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "Convert user Pin Constraint File (.pcf) to an placement file");
shell.set_command_class(shell_cmd_id, cmd_class_id);
shell.set_command_execute_function(shell_cmd_id, pcf2place_wrapper);
return shell_cmd_id;
}
void add_openfpga_setup_commands(openfpga::Shell<OpenfpgaContext>& shell) {
/* Get the unique id of 'vpr' command which is to be used in creating the dependency graph */
const ShellCommandId& vpr_cmd_id = shell.command(std::string("vpr"));
@ -428,6 +473,12 @@ void add_openfpga_setup_commands(openfpga::Shell<OpenfpgaContext>& shell) {
/* Add a new class of commands */
ShellCommandClassId openfpga_setup_cmd_class = shell.add_command_class("OpenFPGA setup");
/********************************
* Command 'pcf2place'
*/
ShellCommandId pcf2place_cmd_id = add_openfpga_pcf2place_command(shell,
openfpga_setup_cmd_class);
/********************************
* Command 'read_openfpga_arch'
*/

View File

@ -17,7 +17,6 @@
#include "openfpga_bitstream_command.h"
#include "openfpga_spice_command.h"
#include "openfpga_sdc_command.h"
#include "openfpga_constrain_pin_location_command.h"
#include "basic_command.h"
#include "openfpga_title.h"
@ -81,9 +80,6 @@ int main(int argc, char** argv) {
/* Add openfpga sdc commands */
openfpga::add_openfpga_sdc_commands(shell);
/* Add constrain pin location command */
openfpga::add_openfpga_constrain_pin_location_command(shell);
/* Add basic commands: exit, help, etc.
* Note:
* This MUST be the last command group to be added!

View File

@ -1,5 +1,5 @@
# Run constrain_pin_location
constrain_pin_location --pcf ${AND2_PIN_CONSTRAIN_FILE} --blif ${VPR_TESTBENCH_BLIF} --pinmap_xml ${AND2_PIN_MAP_XML_FILE} --csv_file ${AND2_PIN_MAP_CSV_FILE} --output ${OPENFPGA_VPR_FIX_PINS_FILE}
# Convert .pcf to a .place file that VPR can accept
pcf2place --pcf ${OPENFPGA_PCF} --blif ${VPR_TESTBENCH_BLIF} --pin_table ${OPENFPGA_PIN_TABLE} --fpga_io_map ${OPENFPGA_IO_MAP_FILE} --fpga_fix_pins ${OPENFPGA_VPR_FIX_PINS_FILE}
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml

View File

@ -0,0 +1,18 @@
<io_coordinates>
<io pad="gfpga_pad_IO_A2F[0]" x="1" y="0" z="0"/>
<io pad="gfpga_pad_IO_F2A[0]" x="1" y="0" z="1"/>
<io pad="gfpga_pad_IO_A2F[1]" x="1" y="0" z="2"/>
<io pad="gfpga_pad_IO_F2A[1]" x="1" y="0" z="3"/>
<io pad="gfpga_pad_IO_A2F[2]" x="1" y="0" z="4"/>
<io pad="gfpga_pad_IO_F2A[2]" x="1" y="0" z="5"/>
<io pad="gfpga_pad_IO_A2F[3]" x="1" y="0" z="6"/>
<io pad="gfpga_pad_IO_F2A[3]" x="1" y="0" z="7"/>
<io pad="gfpga_pad_IO_A2F[4]" x="2" y="0" z="0"/>
<io pad="gfpga_pad_IO_F2A[4]" x="2" y="0" z="1"/>
<io pad="gfpga_pad_IO_A2F[5]" x="2" y="0" z="2"/>
<io pad="gfpga_pad_IO_F2A[5]" x="2" y="0" z="3"/>
<io pad="gfpga_pad_IO_A2F[6]" x="2" y="0" z="4"/>
<io pad="gfpga_pad_IO_F2A[6]" x="2" y="0" z="5"/>
<io pad="gfpga_pad_IO_A2F[7]" x="2" y="0" z="6"/>
<io pad="gfpga_pad_IO_F2A[7]" x="2" y="0" z="7"/>
</io_coordinates>

View File

@ -1,17 +1,17 @@
orientation,row,col,pin_num_in_cell,port_name,mapped_pin,GPIO_type,Associated Clock,Clock Edge
TOP,,,,gfpga_pad_IO_A2F[0],pad_fpga_io[0],,,
TOP,,,,gfpga_pad_IO_F2A[0],pad_fpga_io[0],,,
TOP,,,,gfpga_pad_IO_A2F[4],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_F2A[4],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_A2F[8],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_F2A[8],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_A2F[31],pad_fpga_io[3],,,
TOP,,,,gfpga_pad_IO_F2A[31],pad_fpga_io[3],,,
RIGHT,,,,gfpga_pad_IO_A2F[32],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_F2A[32],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_A2F[40],pad_fpga_io[5],,,
RIGHT,,,,gfpga_pad_IO_F2A[40],pad_fpga_io[5],,,
BOTTOM,,,,gfpga_pad_IO_A2F[64],pad_fpga_io[6],,,
BOTTOM,,,,gfpga_pad_IO_F2A[64],pad_fpga_io[6],,,
LEFT,,,,gfpga_pad_IO_F2A[127],pad_fpga_io[7],,,
LEFT,,,,gfpga_pad_IO_A2F[127],pad_fpga_io[7],,,
TOP,,,,gfpga_pad_IO_A2F[2],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_F2A[2],pad_fpga_io[1],,,
TOP,,,,gfpga_pad_IO_A2F[1],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_F2A[1],pad_fpga_io[2],,,
TOP,,,,gfpga_pad_IO_A2F[3],pad_fpga_io[3],,,
TOP,,,,gfpga_pad_IO_F2A[3],pad_fpga_io[3],,,
RIGHT,,,,gfpga_pad_IO_A2F[5],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_F2A[5],pad_fpga_io[4],,,
RIGHT,,,,gfpga_pad_IO_A2F[4],pad_fpga_io[5],,,
RIGHT,,,,gfpga_pad_IO_F2A[4],pad_fpga_io[5],,,
BOTTOM,,,,gfpga_pad_IO_A2F[6],pad_fpga_io[6],,,
BOTTOM,,,,gfpga_pad_IO_F2A[6],pad_fpga_io[6],,,
LEFT,,,,gfpga_pad_IO_F2A[7],pad_fpga_io[7],,,
LEFT,,,,gfpga_pad_IO_A2F[7],pad_fpga_io[7],,,

1 orientation row col pin_num_in_cell port_name mapped_pin GPIO_type Associated Clock Clock Edge
2 TOP gfpga_pad_IO_A2F[0] pad_fpga_io[0]
3 TOP gfpga_pad_IO_F2A[0] pad_fpga_io[0]
4 TOP gfpga_pad_IO_A2F[4] gfpga_pad_IO_A2F[2] pad_fpga_io[1]
5 TOP gfpga_pad_IO_F2A[4] gfpga_pad_IO_F2A[2] pad_fpga_io[1]
6 TOP gfpga_pad_IO_A2F[8] gfpga_pad_IO_A2F[1] pad_fpga_io[2]
7 TOP gfpga_pad_IO_F2A[8] gfpga_pad_IO_F2A[1] pad_fpga_io[2]
8 TOP gfpga_pad_IO_A2F[31] gfpga_pad_IO_A2F[3] pad_fpga_io[3]
9 TOP gfpga_pad_IO_F2A[31] gfpga_pad_IO_F2A[3] pad_fpga_io[3]
10 RIGHT gfpga_pad_IO_A2F[32] gfpga_pad_IO_A2F[5] pad_fpga_io[4]
11 RIGHT gfpga_pad_IO_F2A[32] gfpga_pad_IO_F2A[5] pad_fpga_io[4]
12 RIGHT gfpga_pad_IO_A2F[40] gfpga_pad_IO_A2F[4] pad_fpga_io[5]
13 RIGHT gfpga_pad_IO_F2A[40] gfpga_pad_IO_F2A[4] pad_fpga_io[5]
14 BOTTOM gfpga_pad_IO_A2F[64] gfpga_pad_IO_A2F[6] pad_fpga_io[6]
15 BOTTOM gfpga_pad_IO_F2A[64] gfpga_pad_IO_F2A[6] pad_fpga_io[6]
16 LEFT gfpga_pad_IO_F2A[127] gfpga_pad_IO_F2A[7] pad_fpga_io[7]
17 LEFT gfpga_pad_IO_A2F[127] gfpga_pad_IO_A2F[7] pad_fpga_io[7]

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
XML file specification is primarily to define the mapping of the interface cell ports defined
in vpr_arch xml, to the EFPGA IO interface port names. This mapping is required by OpenFPGA
alongwith architecture definition file i.e. vpr_arch xml file. OpenFPGA will process this
file and use this information for IO placement and then later on use this to map it with the
user-defined pin-mapping file.
-->
<DEVICE name= "k4_N4_tileable_40nm" family="k4n4" width="6" height="6" z="8">
<IO>
<TOP_IO y="5">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[0:31]" startx="1" endx="4"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[0:31]" startx="1" endx="4"/>
</TOP_IO>
<RIGHT_IO x="5">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[32:63]" starty="4" endy="1"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[32:63]" starty="4" endy="1"/>
</RIGHT_IO>
<BOTTOM_IO y="0">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[64:95]" startx="4" endx="1"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[64:95]" startx="4" endx="1"/>
</BOTTOM_IO>
<LEFT_IO x="0">
<CELL port_name="output" mapped_name="gfpga_pad_IO_F2A[96:127]" starty="1" endy="4"/>
<CELL port_name="input" mapped_name="gfpga_pad_IO_A2F[96:127]" starty="1" endy="4"/>
</LEFT_IO>
</IO>
</DEVICE>

View File

@ -21,10 +21,10 @@ openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_vpr_device_layout=4x4
openfpga_vpr_route_chan_width=20
and2_pin_constrain_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/constrain_pin_location/config/and2.pcf
and2_pin_map_xml_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/constrain_pin_location/config/pinmap_k4_N4_tileable_40nm.xml
and2_pin_map_csv_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/constrain_pin_location/config/pinmap_k4_N4_tileable_40nm.csv
openfpga_vpr_fix_pins_file=./and2_constrain_pin.place
openfpga_pcf=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/constrain_pin_location/config/and2.pcf
openfpga_io_map_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/constrain_pin_location/config/fpga_io_location.xml
openfpga_pin_table=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/constrain_pin_location/config/pinmap_k4_N4_tileable_40nm.csv
openfpga_vpr_fix_pins_file=and2_fix_pins.place
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml