Merge pull request #77 from LNIS-Projects/dev

Misc Updates
This commit is contained in:
Laboratory for Nano Integrated Systems (LNIS) 2020-08-20 09:18:23 -06:00 committed by GitHub
commit 551c2d79c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 3741 additions and 180 deletions

View File

@ -81,6 +81,10 @@ python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/power_gated_design/p
echo -e "Testing Depopulated crossbar in local routing"; echo -e "Testing Depopulated crossbar in local routing";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/depopulate_crossbar --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/depopulate_crossbar --debug --show_thread_logs
echo -e "Testing through channels in tileable routing";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/thru_channel/thru_narrow_tile --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/thru_channel/thru_wide_tile --debug --show_thread_logs
# Verify MCNC big20 benchmark suite with ModelSim # Verify MCNC big20 benchmark suite with ModelSim
# Please make sure you have ModelSim installed in the environment # Please make sure you have ModelSim installed in the environment
# Otherwise, it will fail # Otherwise, it will fail

View File

@ -52,7 +52,7 @@ Layout
.. warning:: Do NOT enable ``through_channel`` if you are not using the tileable routing resource graph generator! .. warning:: Do NOT enable ``through_channel`` if you are not using the tileable routing resource graph generator!
.. warning:: Currently ``through_channel`` supports only a fixed routing channel width! .. warning:: You cannot use ``spread`` pin location for the ``height > 1`` or ``width >1`` tiles when using the tileable routing resource graph!!! Otherwise, it will cause undriven pins in your device!!!
A quick example to show tileable routing is enabled and through channels are disabled: A quick example to show tileable routing is enabled and through channels are disabled:

View File

@ -103,8 +103,9 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
.. note:: OpenFPGA will infer the physical mode for a single-mode ``pb_type`` defined in VPR architecture .. note:: OpenFPGA will infer the physical mode for a single-mode ``pb_type`` defined in VPR architecture
.. option:: <pb_type name="<string>" physical_pb_type_name="<string>" circuit_model_name="<string>" .. option:: <pb_type name="<string>" physical_pb_type_name="<string>"
mode_bits="<int>" physical_pb_type_index_factor="<float>" physical_pb_type_index_offset="<int>"> circuit_model_name="<string>" mode_bits="<int>"
physical_pb_type_index_factor="<float>" physical_pb_type_index_offset="<int>">
Specify the physical implementation for a primitive ``pb_type`` in VPR architecture Specify the physical implementation for a primitive ``pb_type`` in VPR architecture
@ -128,7 +129,8 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
- ``circuit_model_name="<string>"`` For the interconnection type direct, the type of the linked circuit model should be wire. For multiplexers, the type of linked circuit model should be ``mux``. For complete, the type of the linked circuit model can be either ``mux`` or ``wire``, depending on the case. - ``circuit_model_name="<string>"`` For the interconnection type direct, the type of the linked circuit model should be wire. For multiplexers, the type of linked circuit model should be ``mux``. For complete, the type of the linked circuit model can be either ``mux`` or ``wire``, depending on the case.
.. option:: <port name="<string>" physical_mode_port="<string>" physical_mode_pin_rotate_offset="<int>"/> .. option:: <port name="<string>" physical_mode_port="<string>"
physical_mode_pin_initial_offset="<int>" physical_mode_pin_rotate_offset="<int>"/>
Link a port of an operating ``pb_type`` to a port of a physical ``pb_type`` Link a port of an operating ``pb_type`` to a port of a physical ``pb_type``
@ -136,8 +138,39 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
- ``physical_mode_pin="<string>" creates the link of ``port`` of ``pb_type`` between operating and physical modes. This syntax is mandatory for every primitive ``pb_type`` in an operating mode ``pb_type``. It should be a valid ``port`` name of leaf ``pb_type`` in physical mode and the port size should also match. - ``physical_mode_pin="<string>" creates the link of ``port`` of ``pb_type`` between operating and physical modes. This syntax is mandatory for every primitive ``pb_type`` in an operating mode ``pb_type``. It should be a valid ``port`` name of leaf ``pb_type`` in physical mode and the port size should also match.
.. note:: Users can define multiple ports. For example: ``physical_mode_pin="a[0:1] b[2:2]"``. When multiple ports are used, the ``physical_mode_pin_initial_offset`` and ``physical_mode_pin_rotate_offset`` should also be adapt. For example: ``physical_mode_pin_rotate_offset="1 0"``)
- ``physical_mode_pin_initial_offset="<int>"`` aims to align the pin indices for ``port`` of ``pb_type`` between operating and physical modes, especially when part of port of operating mode is mapped to a port in physical ``pb_type``. When ``physical_mode_pin_initial_offset`` is larger than zero, the pin index of ``pb_type`` (whose index is large than 1) will be shifted by the given offset.
.. note:: A quick example to understand the initial offset
For example, an initial offset of -32 is used to map
- operating pb_type ``bram[0].dout[32]`` with a full path ``memory[dual_port].bram[0]``
- operating pb_type ``bram[0].dout[33]`` with a full path ``memory[dual_port].bram[0]``
to
- physical pb_type ``bram[0].dout_a[0]`` with a full path ``memory[physical].bram[0]``
- physical pb_type ``bram[0].dout_a[1]`` with a full path ``memory[physical].bram[0]``
.. note:: If not defined, the default value of ``physical_mode_pin_initial_offset`` is set to ``0``.
- ``physical_mode_pin_rotate_offset="<int>"`` aims to align the pin indices for ``port`` of ``pb_type`` between operating and physical modes, especially when an operating mode contains multiple ``pb_type`` (``num_pb``>1) that are linked to the same physical ``pb_type``. When ``physical_mode_pin_rotate_offset`` is larger than zero, the pin index of ``pb_type`` (whose index is large than 1) will be shifted by the given offset. - ``physical_mode_pin_rotate_offset="<int>"`` aims to align the pin indices for ``port`` of ``pb_type`` between operating and physical modes, especially when an operating mode contains multiple ``pb_type`` (``num_pb``>1) that are linked to the same physical ``pb_type``. When ``physical_mode_pin_rotate_offset`` is larger than zero, the pin index of ``pb_type`` (whose index is large than 1) will be shifted by the given offset.
.. note:: A quick example to understand the rotate offset
For example, a rotating offset of 9 is used to map
- operating pb_type ``mult_9x9[0].a[0:8]`` with a full path ``mult[frac].mult_9x9[0]``
- operating pb_type ``mult_9x9[1].a[0:8]`` with a full path ``mult[frac].mult_9x9[1]``
to
- physical pb_type ``mult_36x36.a[0:8]`` with a full path ``mult[physical].mult_36x36[0]``
- physical pb_type ``mult_36x36.a[9:17]`` with a full path ``mult[physical].mult_36x36[0]``
.. note:: If not defined, the default value of ``physical_mode_pin_rotate_offset`` is set to ``0``.
.. note:: .. note::
It is highly recommended that only one physical mode is defined for a multi-mode configurable block. Try not to use nested physical mode definition. This will ease the debugging and lead to clean XML description. It is highly recommended that only one physical mode is defined for a multi-mode configurable block. Try not to use nested physical mode definition. This will ease the debugging and lead to clean XML description.

View File

@ -7,6 +7,6 @@ Design Flows
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
blif_to_verification verilog2verification
verilog_to_gds2 verilog2gds2

View File

@ -1,7 +1,7 @@
.. _from_blif_to_verification: .. _from_verilog_to_verification:
From BLIF to Verification From Verilog to Verification
------------------------- ----------------------------
This tutorial will show an example how to This tutorial will show an example how to
- generate Verilog netlists for a FPGA fabric - generate Verilog netlists for a FPGA fabric

View File

@ -1,6 +1,7 @@
/************************************************************************ /************************************************************************
* Member functions for class PbTypeAnnotation * Member functions for class PbTypeAnnotation
***********************************************************************/ ***********************************************************************/
#include <algorithm>
#include "vtr_log.h" #include "vtr_log.h"
#include "vtr_assert.h" #include "vtr_assert.h"
#include "pb_type_annotation.h" #include "pb_type_annotation.h"
@ -85,24 +86,15 @@ std::vector<std::string> PbTypeAnnotation::port_names() const {
return keys; return keys;
} }
BasicPort PbTypeAnnotation::physical_pb_type_port(const std::string& port_name) const { std::map<BasicPort, std::array<int, 2>> PbTypeAnnotation::physical_pb_type_port(const std::string& port_name) const {
std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(port_name); std::map<std::string, std::map<BasicPort, std::array<int, 2>>>::const_iterator it = operating_pb_type_ports_.find(port_name);
if (it == operating_pb_type_ports_.end()) { if (it == operating_pb_type_ports_.end()) {
/* Return an empty port */ /* Return an empty port */
return BasicPort(); return std::map<BasicPort, std::array<int, 2>>();
} }
return operating_pb_type_ports_.at(port_name); return operating_pb_type_ports_.at(port_name);
} }
int PbTypeAnnotation::physical_pin_rotate_offset(const std::string& port_name) const {
std::map<std::string, int>::const_iterator it = physical_pin_rotate_offsets_.find(port_name);
if (it == physical_pin_rotate_offsets_.end()) {
/* Return a zero offset which is default */
return 0;
}
return physical_pin_rotate_offsets_.at(port_name);
}
std::vector<std::string> PbTypeAnnotation::interconnect_names() const { std::vector<std::string> PbTypeAnnotation::interconnect_names() const {
std::vector<std::string> keys; std::vector<std::string> keys;
for (auto const& element : interconnect_circuit_model_names_) { for (auto const& element : interconnect_circuit_model_names_) {
@ -177,27 +169,65 @@ void PbTypeAnnotation::set_physical_pb_type_index_offset(const int& value) {
void PbTypeAnnotation::add_pb_type_port_pair(const std::string& operating_pb_port_name, void PbTypeAnnotation::add_pb_type_port_pair(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port) { const BasicPort& physical_pb_port) {
/* Give a warning if the operating_pb_port_name already exist */ /* Give a warning if the operating_pb_port_name already exist */
std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name); std::map<std::string, std::map<BasicPort, std::array<int, 2>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
/* Give a warning if the interconnection name already exist */
if (it != operating_pb_type_ports_.end()) {
VTR_LOG_WARN("Redefine operating pb type port '%s' with physical pb type port '%s'\n",
operating_pb_port_name.c_str(), physical_pb_port.get_name().c_str());
}
operating_pb_type_ports_[operating_pb_port_name] = physical_pb_port; /* If not exist, initialize and set a default value */
}
void PbTypeAnnotation::set_physical_pin_rotate_offset(const std::string& operating_pb_port_name,
const int& physical_pin_rotate_offset) {
std::map<std::string, BasicPort>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
/* Give a warning if the interconnection name already exist */
if (it == operating_pb_type_ports_.end()) { if (it == operating_pb_type_ports_.end()) {
VTR_LOG_ERROR("Operating pb type port '%s' does not exist! Ignore physical pin rotate offset '%d'\n", operating_pb_type_ports_[operating_pb_port_name][physical_pb_port] = {0, 0};
operating_pb_port_name.c_str(), physical_pin_rotate_offset); /* We can return early */
return; return;
} }
physical_pin_rotate_offsets_[operating_pb_port_name] = physical_pin_rotate_offset; /* If the physical port is not in the list, we create one and set a default value */
if (0 == operating_pb_type_ports_[operating_pb_port_name].count(physical_pb_port)) {
operating_pb_type_ports_[operating_pb_port_name][physical_pb_port] = {0, 0};
}
}
void PbTypeAnnotation::set_physical_pin_initial_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port,
const int& physical_pin_initial_offset) {
std::map<std::string, std::map<BasicPort, std::array<int, 2>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
if (it == operating_pb_type_ports_.end()) {
VTR_LOG_ERROR("The operating pb_type port '%s' is not valid!\n",
operating_pb_port_name.c_str());
exit(1);
}
if (operating_pb_type_ports_[operating_pb_port_name].end() == operating_pb_type_ports_[operating_pb_port_name].find(physical_pb_port)) {
VTR_LOG_ERROR("The physical pb_type port '%s[%lu:%lu]' definition for operating pb_type port '%s' is not valid!\n",
physical_pb_port.get_name().c_str(),
physical_pb_port.get_lsb(),
physical_pb_port.get_msb(),
operating_pb_port_name.c_str());
exit(1);
}
operating_pb_type_ports_[operating_pb_port_name][physical_pb_port][0] = physical_pin_initial_offset;
}
void PbTypeAnnotation::set_physical_pin_rotate_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port,
const int& physical_pin_rotate_offset) {
std::map<std::string, std::map<BasicPort, std::array<int, 2>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
if (it == operating_pb_type_ports_.end()) {
VTR_LOG_ERROR("The operating pb_type port '%s' is not valid!\n",
operating_pb_port_name.c_str());
exit(1);
}
if (operating_pb_type_ports_[operating_pb_port_name].end() == operating_pb_type_ports_[operating_pb_port_name].find(physical_pb_port)) {
VTR_LOG_ERROR("The physical pb_type port '%s[%lu:%lu]' definition for operating pb_type port '%s' is not valid!\n",
physical_pb_port.get_name().c_str(),
physical_pb_port.get_lsb(),
physical_pb_port.get_msb(),
operating_pb_port_name.c_str());
exit(1);
}
operating_pb_type_ports_[operating_pb_port_name][physical_pb_port][1] = physical_pin_rotate_offset;
} }
void PbTypeAnnotation::add_interconnect_circuit_model_pair(const std::string& interc_name, void PbTypeAnnotation::add_interconnect_circuit_model_pair(const std::string& interc_name,

View File

@ -6,6 +6,7 @@
*******************************************************************/ *******************************************************************/
#include <vector> #include <vector>
#include <map> #include <map>
#include <array>
#include "openfpga_port.h" #include "openfpga_port.h"
@ -48,8 +49,7 @@ class PbTypeAnnotation {
float physical_pb_type_index_factor() const; float physical_pb_type_index_factor() const;
int physical_pb_type_index_offset() const; int physical_pb_type_index_offset() const;
std::vector<std::string> port_names() const; std::vector<std::string> port_names() const;
BasicPort physical_pb_type_port(const std::string& port_name) const; std::map<BasicPort, std::array<int, 2>> physical_pb_type_port(const std::string& port_name) const;
int physical_pin_rotate_offset(const std::string& port_name) const;
std::vector<std::string> interconnect_names() const; std::vector<std::string> interconnect_names() const;
std::string interconnect_circuit_model_name(const std::string& interc_name) const; std::string interconnect_circuit_model_name(const std::string& interc_name) const;
public: /* Public mutators */ public: /* Public mutators */
@ -67,7 +67,11 @@ class PbTypeAnnotation {
void set_physical_pb_type_index_offset(const int& value); void set_physical_pb_type_index_offset(const int& value);
void add_pb_type_port_pair(const std::string& operating_pb_port_name, void add_pb_type_port_pair(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port); const BasicPort& physical_pb_port);
void set_physical_pin_initial_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port,
const int& physical_pin_initial_offset);
void set_physical_pin_rotate_offset(const std::string& operating_pb_port_name, void set_physical_pin_rotate_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port,
const int& physical_pin_rotate_offset); const int& physical_pin_rotate_offset);
void add_interconnect_circuit_model_pair(const std::string& interc_name, void add_interconnect_circuit_model_pair(const std::string& interc_name,
const std::string& circuit_model_name); const std::string& circuit_model_name);
@ -133,10 +137,13 @@ class PbTypeAnnotation {
*/ */
int physical_pb_type_index_offset_; int physical_pb_type_index_offset_;
/* Link from the pins under an operating pb_type to physical pb_type */ /* Link from the pins under an operating pb_type to pairs of
std::map<std::string, BasicPort> operating_pb_type_ports_; * its physical pb_type and its pin initial & rotating offset
*
/* The offset aims to align the pin indices for port of pb_type * Note that initial offset is the first element of the std::array
* Note that rotating offset is the second element of the std::array
*
* The offsets aim to align the pin indices for port of pb_type
* between operating and physical modes, especially when an operating * between operating and physical modes, especially when an operating
* mode contains multiple pb_type (num_pb>1) that are linked to * mode contains multiple pb_type (num_pb>1) that are linked to
* the same physical pb_type. * the same physical pb_type.
@ -144,11 +151,21 @@ class PbTypeAnnotation {
* the pin index of pb_type (whose index is large than 1) * the pin index of pb_type (whose index is large than 1)
* will be shifted by the given offset. * will be shifted by the given offset.
* *
* For example, an offset of 1 is used to map * For example, an initial offset of -32 is used to map
* operating pb_type adder[0].pin[0] with a full path clb.fle[arith].adder[0] * operating pb_type bram[0].dout[32] with a full path memory[dual_port].bram[0]
* to physical pb_type adder[0].pin[1] with a full path clb.fle[physical].adder[0] * operating pb_type bram[0].dout[33] with a full path memory[dual_port].bram[0]
* to
* physical pb_type bram[0].dout_a[0] with a full path memory[physical].bram[0]
* physical pb_type bram[0].dout_a[1] with a full path memory[physical].bram[0]
*
* For example, a rotating offset of 9 is used to map
* operating pb_type mult_9x9[0].a[0:8] with a full path mult[frac].mult_9x9[0]
* operating pb_type mult_9x9[1].a[0:8] with a full path mult[frac].mult_9x9[1]
* to
* physical pb_type mult_36x36.a[0:8] with a full path mult[physical].mult_36x36[0]
* physical pb_type mult_36x36.a[9:17] with a full path mult[physical].mult_36x36[0]
*/ */
std::map<std::string, int> physical_pin_rotate_offsets_; std::map<std::string, std::map<BasicPort, std::array<int, 2>>> operating_pb_type_ports_;
/* Link between the interconnects under this pb_type and circuit model names */ /* Link between the interconnects under this pb_type and circuit model names */
std::map<std::string, std::string> interconnect_circuit_model_names_; std::map<std::string, std::string> interconnect_circuit_model_names_;

View File

@ -55,12 +55,65 @@ void read_xml_pb_port_annotation(pugi::xml_node& xml_port,
const std::string& name_attr = get_attribute(xml_port, "name", loc_data).as_string(); const std::string& name_attr = get_attribute(xml_port, "name", loc_data).as_string();
const std::string& physical_mode_port_attr = get_attribute(xml_port, "physical_mode_port", loc_data).as_string(); const std::string& physical_mode_port_attr = get_attribute(xml_port, "physical_mode_port", loc_data).as_string();
/* Parse the mode port using openfpga port parser */ /* Split the physical mode port attributes with space */
openfpga::PortParser port_parser(physical_mode_port_attr); openfpga::StringToken port_tokenizer(physical_mode_port_attr);
pb_type_annotation.add_pb_type_port_pair(name_attr, port_parser.port()); const std::vector<std::string> physical_mode_ports = port_tokenizer.split();
/* We have an optional attribute: physical_mode_pin_rotate_offset */ /* Parse the mode port using openfpga port parser */
pb_type_annotation.set_physical_pin_rotate_offset(name_attr, get_attribute(xml_port, "physical_mode_pin_rotate_offset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(0)); for (const auto& physical_mode_port : physical_mode_ports) {
openfpga::PortParser port_parser(physical_mode_port);
pb_type_annotation.add_pb_type_port_pair(name_attr, port_parser.port());
}
/* We have an optional attribute: physical_mode_pin_initial_offset
* Split based on the number of physical pb_type ports that have been defined
*/
const std::string& physical_pin_initial_offset_attr = get_attribute(xml_port, "physical_mode_pin_initial_offset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string();
if (false == physical_pin_initial_offset_attr.empty()) {
/* Split the physical mode port attributes with space */
openfpga::StringToken offset_tokenizer(physical_pin_initial_offset_attr);
const std::vector<std::string> initial_offsets = offset_tokenizer.split();
/* Error out if the offset does not match the port definition */
if (physical_mode_ports.size() != initial_offsets.size()) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_port),
"Defined %lu physical mode ports but only %lu physical pin initial offset are defined! Expect size matching.\n",
physical_mode_ports.size(), initial_offsets.size());
}
for (size_t iport = 0; iport < physical_mode_ports.size(); ++iport) {
openfpga::PortParser port_parser(physical_mode_ports[iport]);
pb_type_annotation.set_physical_pin_initial_offset(name_attr,
port_parser.port(),
std::stoi(initial_offsets[iport]));
}
}
/* We have an optional attribute: physical_mode_pin_rotate_offset
* Split based on the number of physical pb_type ports that have been defined
*/
const std::string& physical_pin_rotate_offset_attr = get_attribute(xml_port, "physical_mode_pin_rotate_offset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string();
if (false == physical_pin_rotate_offset_attr.empty()) {
/* Split the physical mode port attributes with space */
openfpga::StringToken offset_tokenizer(physical_pin_rotate_offset_attr);
const std::vector<std::string> rotate_offsets = offset_tokenizer.split();
/* Error out if the offset does not match the port definition */
if (physical_mode_ports.size() != rotate_offsets.size()) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_port),
"Defined %lu physical mode ports but only %lu physical pin rotate offset are defined! Expect size matching.\n",
physical_mode_ports.size(), rotate_offsets.size());
}
for (size_t iport = 0; iport < physical_mode_ports.size(); ++iport) {
openfpga::PortParser port_parser(physical_mode_ports[iport]);
pb_type_annotation.set_physical_pin_rotate_offset(name_attr,
port_parser.port(),
std::stoi(rotate_offsets[iport]));
}
}
} }
/******************************************************************** /********************************************************************

View File

@ -116,8 +116,33 @@ void write_xml_pb_port_annotation(std::fstream& fp,
fp << "\t\t\t" << "<port"; fp << "\t\t\t" << "<port";
write_xml_attribute(fp, "name", port_name.c_str()); write_xml_attribute(fp, "name", port_name.c_str());
write_xml_attribute(fp, "physical_mode_port", generate_physical_pb_port_name(pb_type_annotation.physical_pb_type_port(port_name)).c_str());
write_xml_attribute(fp, "physical_mode_pin_rotate_offset", pb_type_annotation.physical_pin_rotate_offset(port_name)); std::string physical_mode_port_attr;
for (const auto& physical_pb_port_pair : pb_type_annotation.physical_pb_type_port(port_name)) {
if (false == physical_mode_port_attr.empty()) {
physical_mode_port_attr += " ";
}
physical_mode_port_attr += generate_physical_pb_port_name(physical_pb_port_pair.first);
}
write_xml_attribute(fp, "physical_mode_port", physical_mode_port_attr.c_str());
std::string physical_mode_pin_initial_offset_attr;
for (const auto& physical_pb_port_pair : pb_type_annotation.physical_pb_type_port(port_name)) {
if (false == physical_mode_pin_initial_offset_attr.empty()) {
physical_mode_pin_initial_offset_attr += " ";
}
physical_mode_pin_initial_offset_attr += std::to_string(physical_pb_port_pair.second[0]);
}
write_xml_attribute(fp, "physical_mode_pin_initial_offset", physical_mode_pin_initial_offset_attr.c_str());
std::string physical_mode_pin_rotate_offset_attr;
for (const auto& physical_pb_port_pair : pb_type_annotation.physical_pb_type_port(port_name)) {
if (false == physical_mode_pin_rotate_offset_attr.empty()) {
physical_mode_pin_rotate_offset_attr += " ";
}
physical_mode_pin_rotate_offset_attr += std::to_string(physical_pb_port_pair.second[1]);
}
write_xml_attribute(fp, "physical_mode_pin_rotate_offset", physical_mode_pin_rotate_offset_attr.c_str());
fp << "/>" << "\n"; fp << "/>" << "\n";
} }

View File

@ -124,6 +124,16 @@ bool BasicPort::operator== (const BasicPort& portA) const {
return false; return false;
} }
bool BasicPort::operator< (const BasicPort& portA) const {
if ( (0 == this->get_name().compare(portA.get_name()))
&& (this->get_lsb() < portA.get_lsb())
&& (this->get_msb() < portA.get_msb()) ) {
return true;
}
return false;
}
/************************************************************************ /************************************************************************
* Mutators * Mutators
***********************************************************************/ ***********************************************************************/

View File

@ -21,6 +21,7 @@ class BasicPort {
BasicPort(const BasicPort& basic_port); /* Copy constructor */ BasicPort(const BasicPort& basic_port); /* Copy constructor */
public: /* Overloaded operators */ public: /* Overloaded operators */
bool operator== (const BasicPort& portA) const; bool operator== (const BasicPort& portA) const;
bool operator< (const BasicPort& portA) const;
public: /* Accessors */ public: /* Accessors */
size_t get_width() const; /* get the port width */ size_t get_width() const; /* get the port width */
size_t get_msb() const; /* get the LSB */ size_t get_msb() const; /* get the LSB */

View File

@ -306,35 +306,50 @@ bool try_match_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin,
t_pb_graph_pin* physical_pb_graph_pin, t_pb_graph_pin* physical_pb_graph_pin,
const VprDeviceAnnotation& vpr_device_annotation) { const VprDeviceAnnotation& vpr_device_annotation) {
/* If the parent ports of the two pins are not paired, fail */ /* If the parent ports of the two pins are not paired, fail */
if (physical_pb_graph_pin->port != vpr_device_annotation.physical_pb_port(operating_pb_graph_pin->port)) { for (t_port* candidate_port : vpr_device_annotation.physical_pb_port(operating_pb_graph_pin->port)) {
return false; if (physical_pb_graph_pin->port != candidate_port) {
} /* Not the one we want, try the next candidate */
/* Check the pin number of physical pb_graph_pin matches the pin number of continue;
* operating pb_graph_pin plus a rotation offset }
* operating port physical port /* Check the pin number of physical pb_graph_pin matches the pin number of
* LSB port_range.lsb() pin_number pin_number MSB * operating pb_graph_pin plus a rotation offset with an initial offset,
* | | | * which is to align the lsb between operating and physical ports
* Operating port | | +------ | *
* | |<----offset--->| * For example:
* Physical port | + + + * We can align the operating_port[32] to physical_port[0] with an initial offset
* * which is -32
* Note: *
* - accumulated offset is NOT the pin rotate offset specified by users * operating port physical port
* It is an aggregation of the offset during pin pairing * LSB port_range.lsb() pin_number pin_number MSB
* Each time, we manage to pair two pins, the accumulated offset will be incremented * | | init_offset |
* by the pin rotate offset value * Operating port | | +------ + |
* The accumulated offset will be reset to 0 when it exceeds the msb() of the physical port * | |<----acc_offset--->|
*/ * Physical port | + + +
int acc_offset = vpr_device_annotation.physical_pb_pin_offset(operating_pb_graph_pin->port); *
const BasicPort& physical_port_range = vpr_device_annotation.physical_pb_port_range(operating_pb_graph_pin->port); * Note:
if (physical_pb_graph_pin->pin_number != operating_pb_graph_pin->pin_number * - accumulated offset is NOT the pin rotate offset specified by users
+ (int)physical_port_range.get_lsb() * It is an aggregation of the offset during pin pairing
+ acc_offset) { * Each time, we manage to pair two pins, the accumulated offset will be incremented
return false; * by the pin rotate offset value
* The accumulated offset will be reset to 0 when it exceeds the msb() of the physical port
*/
int acc_offset = vpr_device_annotation.physical_pb_pin_offset(operating_pb_graph_pin->port, candidate_port);
int init_offset = vpr_device_annotation.physical_pb_pin_initial_offset(operating_pb_graph_pin->port, candidate_port);
const BasicPort& physical_port_range = vpr_device_annotation.physical_pb_port_range(operating_pb_graph_pin->port, candidate_port);
if (physical_pb_graph_pin->pin_number != operating_pb_graph_pin->pin_number
+ (int)physical_port_range.get_lsb()
+ init_offset
+ acc_offset) {
/* Not the one we want, try the next candidate */
continue;
}
/* Reach here, it means all the requirements have been met */
return true;
} }
/* Reach here, it means all the requirements have been met */ /* If we reach here, we failed */
return true; return false;
} }
/******************************************************************** /********************************************************************
@ -424,7 +439,7 @@ void annotate_physical_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin,
/* If we reach here, it means that pin pairing fails, error out! */ /* If we reach here, it means that pin pairing fails, error out! */
VTR_LOG_ERROR("Fail to match a physical pin for '%s' from pb_graph_node '%s'!\n", VTR_LOG_ERROR("Fail to match a physical pin for '%s' from pb_graph_node '%s'!\n",
operating_pb_graph_pin->port->name, operating_pb_graph_pin->to_string().c_str(),
physical_pb_graph_node->hierarchical_type_name().c_str()); physical_pb_graph_node->hierarchical_type_name().c_str());
} }

View File

@ -211,32 +211,39 @@ bool pair_operating_and_physical_pb_types(t_pb_type* operating_pb_type,
* if not found, we assume that the physical port is the same as the operating pb_port * if not found, we assume that the physical port is the same as the operating pb_port
*/ */
for (t_port* operating_pb_port : pb_type_ports(operating_pb_type)) { for (t_port* operating_pb_port : pb_type_ports(operating_pb_type)) {
/* Try to find the port in the pb_type_annotation */ std::map<BasicPort, std::array<int, 2>> expected_physical_pb_ports = pb_type_annotation.physical_pb_type_port(std::string(operating_pb_port->name));
BasicPort expected_physical_pb_port = pb_type_annotation.physical_pb_type_port(std::string(operating_pb_port->name));
if (true == expected_physical_pb_port.get_name().empty()) { /* If not defined in the annotation, set the default pair:
/* Not found, we reset the port information to be consistent as the operating pb_port */ * rotate_offset is 0 by default!
*/
if (true == expected_physical_pb_ports.empty()) {
BasicPort expected_physical_pb_port;
expected_physical_pb_port.set_name(std::string(operating_pb_port->name)); expected_physical_pb_port.set_name(std::string(operating_pb_port->name));
expected_physical_pb_port.set_width(operating_pb_port->num_pins); expected_physical_pb_port.set_width(operating_pb_port->num_pins);
expected_physical_pb_ports[expected_physical_pb_port] = {0, 0};
} }
/* Try to find the expected port in the physical pb_type */ for (const auto& expected_physical_pb_port : expected_physical_pb_ports) {
t_port* physical_pb_port = find_pb_type_port(physical_pb_type, expected_physical_pb_port.get_name()); /* Try to find the expected port in the physical pb_type */
/* Not found, mapping fails */ t_port* physical_pb_port = find_pb_type_port(physical_pb_type, expected_physical_pb_port.first.get_name());
if (nullptr == physical_pb_port) { /* Not found, mapping fails */
return false; if (nullptr == physical_pb_port) {
return false;
}
/* If the port range does not match, mapping fails */
if (false == BasicPort(physical_pb_port->name, physical_pb_port->num_pins).contained(expected_physical_pb_port.first)) {
return false;
}
/* Now, port mapping should succeed, we update the vpr_device_annotation
* - port binding
* - port range
* - port pin rotate offset
*/
vpr_device_annotation.add_physical_pb_port(operating_pb_port, physical_pb_port);
vpr_device_annotation.add_physical_pb_port_range(operating_pb_port, physical_pb_port, expected_physical_pb_port.first);
vpr_device_annotation.add_physical_pb_pin_initial_offset(operating_pb_port, physical_pb_port, expected_physical_pb_port.second[0]);
vpr_device_annotation.add_physical_pb_pin_rotate_offset(operating_pb_port, physical_pb_port, expected_physical_pb_port.second[1]);
} }
/* If the port range does not match, mapping fails */
if (false == BasicPort(physical_pb_port->name, physical_pb_port->num_pins).contained(expected_physical_pb_port)) {
return false;
}
/* Now, port mapping should succeed, we update the vpr_device_annotation
* - port binding
* - port range
* - port pin rotate offset
*/
vpr_device_annotation.add_physical_pb_port(operating_pb_port, physical_pb_port);
vpr_device_annotation.add_physical_pb_port_range(operating_pb_port, expected_physical_pb_port);
vpr_device_annotation.add_physical_pb_pin_rotate_offset(operating_pb_port, pb_type_annotation.physical_pin_rotate_offset(std::string(operating_pb_port->name)));
} }
/* Now, pb_type mapping should succeed, we update the vpr_device_annotation /* Now, pb_type mapping should succeed, we update the vpr_device_annotation
@ -365,7 +372,7 @@ bool self_pair_physical_pb_types(t_pb_type* physical_pb_type,
for (t_port* physical_pb_port : pb_type_ports(physical_pb_type)) { for (t_port* physical_pb_port : pb_type_ports(physical_pb_type)) {
BasicPort physical_port_range(physical_pb_port->name, physical_pb_port->num_pins); BasicPort physical_port_range(physical_pb_port->name, physical_pb_port->num_pins);
vpr_device_annotation.add_physical_pb_port(physical_pb_port, physical_pb_port); vpr_device_annotation.add_physical_pb_port(physical_pb_port, physical_pb_port);
vpr_device_annotation.add_physical_pb_port_range(physical_pb_port, physical_port_range); vpr_device_annotation.add_physical_pb_port_range(physical_pb_port, physical_pb_port, physical_port_range);
} }
/* Now, pb_type mapping should succeed, we update the vpr_device_annotation */ /* Now, pb_type mapping should succeed, we update the vpr_device_annotation */

View File

@ -114,7 +114,7 @@ void check_vpr_physical_primitive_pb_type_annotation(t_pb_type* cur_pb_type,
/* Now we need to check each port of the pb_type */ /* Now we need to check each port of the pb_type */
for (t_port* pb_port : pb_type_ports(cur_pb_type)) { for (t_port* pb_port : pb_type_ports(cur_pb_type)) {
if (nullptr == vpr_device_annotation.physical_pb_port(pb_port)) { if (0 == vpr_device_annotation.physical_pb_port(pb_port).size()) {
VTR_LOG_ERROR("Find a port '%s' of pb_type '%s' which has not been mapped to any physical port!\n", VTR_LOG_ERROR("Find a port '%s' of pb_type '%s' which has not been mapped to any physical port!\n",
pb_port->name, cur_pb_type->name); pb_port->name, cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n"); VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");

View File

@ -48,23 +48,28 @@ t_pb_type* VprDeviceAnnotation::physical_pb_type(t_pb_type* pb_type) const {
return physical_pb_types_.at(pb_type); return physical_pb_types_.at(pb_type);
} }
t_port* VprDeviceAnnotation::physical_pb_port(t_port* pb_port) const { std::vector<t_port*> VprDeviceAnnotation::physical_pb_port(t_port* pb_port) const {
/* Ensure that the pb_type is in the list */ /* Ensure that the pb_type is in the list */
std::map<t_port*, t_port*>::const_iterator it = physical_pb_ports_.find(pb_port); std::map<t_port*, std::vector<t_port*>>::const_iterator it = physical_pb_ports_.find(pb_port);
if (it == physical_pb_ports_.end()) { if (it == physical_pb_ports_.end()) {
return nullptr; return std::vector<t_port*>();
} }
return physical_pb_ports_.at(pb_port); return physical_pb_ports_.at(pb_port);
} }
BasicPort VprDeviceAnnotation::physical_pb_port_range(t_port* pb_port) const { BasicPort VprDeviceAnnotation::physical_pb_port_range(t_port* operating_pb_port,
t_port* physical_pb_port) const {
/* Ensure that the pb_type is in the list */ /* Ensure that the pb_type is in the list */
std::map<t_port*, BasicPort>::const_iterator it = physical_pb_port_ranges_.find(pb_port); std::map<t_port*, std::map<t_port*, BasicPort>>::const_iterator it = physical_pb_port_ranges_.find(operating_pb_port);
if (it == physical_pb_port_ranges_.end()) { if (it == physical_pb_port_ranges_.end()) {
/* Return an invalid port. As such the port width will be 0, which is an invalid value */ /* Return an invalid port. As such the port width will be 0, which is an invalid value */
return BasicPort(); return BasicPort();
} }
return physical_pb_port_ranges_.at(pb_port); if (0 == physical_pb_port_ranges_.at(operating_pb_port).count(physical_pb_port)) {
/* Return an invalid port. As such the port width will be 0, which is an invalid value */
return BasicPort();
}
return physical_pb_port_ranges_.at(operating_pb_port).at(physical_pb_port);
} }
CircuitModelId VprDeviceAnnotation::pb_type_circuit_model(t_pb_type* physical_pb_type) const { CircuitModelId VprDeviceAnnotation::pb_type_circuit_model(t_pb_type* physical_pb_type) const {
@ -185,27 +190,51 @@ int VprDeviceAnnotation::physical_pb_type_index_offset(t_pb_type* pb_type) const
return physical_pb_type_index_offsets_.at(pb_type); return physical_pb_type_index_offsets_.at(pb_type);
} }
int VprDeviceAnnotation::physical_pb_pin_rotate_offset(t_port* pb_port) const { int VprDeviceAnnotation::physical_pb_pin_initial_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const {
/* Ensure that the pb_type is in the list */ /* Ensure that the pb_type is in the list */
std::map<t_port*, int>::const_iterator it = physical_pb_pin_rotate_offsets_.find(pb_port); std::map<t_port*, std::map<t_port*, int>>::const_iterator it = physical_pb_pin_initial_offsets_.find(operating_pb_port);
if (it == physical_pb_pin_initial_offsets_.end()) {
/* Default value is 0 */
return 0;
}
if (0 == physical_pb_pin_initial_offsets_.at(operating_pb_port).count(physical_pb_port)) {
/* Default value is 0 */
return 0;
}
return physical_pb_pin_initial_offsets_.at(operating_pb_port).at(physical_pb_port);
}
int VprDeviceAnnotation::physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const {
/* Ensure that the pb_type is in the list */
std::map<t_port*, std::map<t_port*, int>>::const_iterator it = physical_pb_pin_rotate_offsets_.find(operating_pb_port);
if (it == physical_pb_pin_rotate_offsets_.end()) { if (it == physical_pb_pin_rotate_offsets_.end()) {
/* Default value is 0 */ /* Default value is 0 */
return 0; return 0;
} }
return physical_pb_pin_rotate_offsets_.at(pb_port); if (0 == physical_pb_pin_rotate_offsets_.at(operating_pb_port).count(physical_pb_port)) {
/* Default value is 0 */
return 0;
}
return physical_pb_pin_rotate_offsets_.at(operating_pb_port).at(physical_pb_port);
} }
int VprDeviceAnnotation::physical_pb_pin_offset(t_port* pb_port) const { int VprDeviceAnnotation::physical_pb_pin_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const {
/* Ensure that the pb_type is in the list */ /* Ensure that the pb_type is in the list */
std::map<t_port*, int>::const_iterator it = physical_pb_pin_offsets_.find(pb_port); std::map<t_port*, std::map<t_port*, int>>::const_iterator it = physical_pb_pin_offsets_.find(operating_pb_port);
if (it == physical_pb_pin_offsets_.end()) { if (it == physical_pb_pin_offsets_.end()) {
/* Default value is 0 */ /* Default value is 0 */
return 0; return 0;
} }
return physical_pb_pin_offsets_.at(pb_port); if (0 == physical_pb_pin_offsets_.at(operating_pb_port).count(physical_pb_port)) {
/* Default value is 0 */
return 0;
}
return physical_pb_pin_offsets_.at(operating_pb_port).at(physical_pb_port);
} }
t_pb_graph_pin* VprDeviceAnnotation::physical_pb_graph_pin(const t_pb_graph_pin* pb_graph_pin) const { t_pb_graph_pin* VprDeviceAnnotation::physical_pb_graph_pin(const t_pb_graph_pin* pb_graph_pin) const {
/* Ensure that the pb_type is in the list */ /* Ensure that the pb_type is in the list */
std::map<const t_pb_graph_pin*, t_pb_graph_pin*>::const_iterator it = physical_pb_graph_pins_.find(pb_graph_pin); std::map<const t_pb_graph_pin*, t_pb_graph_pin*>::const_iterator it = physical_pb_graph_pins_.find(pb_graph_pin);
@ -274,29 +303,28 @@ void VprDeviceAnnotation::add_physical_pb_type(t_pb_type* operating_pb_type, t_p
physical_pb_types_[operating_pb_type] = physical_pb_type; physical_pb_types_[operating_pb_type] = physical_pb_type;
} }
void VprDeviceAnnotation::add_physical_pb_port(t_port* operating_pb_port, t_port* physical_pb_port) { void VprDeviceAnnotation::add_physical_pb_port(t_port* operating_pb_port,
/* Warn any override attempt */ t_port* physical_pb_port) {
std::map<t_port*, t_port*>::const_iterator it = physical_pb_ports_.find(operating_pb_port); physical_pb_ports_[operating_pb_port].push_back(physical_pb_port);
if (it != physical_pb_ports_.end()) {
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port '%s'!\n",
operating_pb_port->name, physical_pb_port->name);
}
physical_pb_ports_[operating_pb_port] = physical_pb_port;
} }
void VprDeviceAnnotation::add_physical_pb_port_range(t_port* operating_pb_port, const BasicPort& port_range) { void VprDeviceAnnotation::add_physical_pb_port_range(t_port* operating_pb_port,
t_port* physical_pb_port,
const BasicPort& port_range) {
/* The port range must satify the port width*/ /* The port range must satify the port width*/
VTR_ASSERT((size_t)operating_pb_port->num_pins == port_range.get_width()); VTR_ASSERT((size_t)operating_pb_port->num_pins >= port_range.get_width());
/* Warn any override attempt */ /* Warn any override attempt */
std::map<t_port*, BasicPort>::const_iterator it = physical_pb_port_ranges_.find(operating_pb_port); std::map<t_port*, std::map<t_port*, BasicPort>>::const_iterator it = physical_pb_port_ranges_.find(operating_pb_port);
if (it != physical_pb_port_ranges_.end()) { if ( (it != physical_pb_port_ranges_.end())
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port range '[%ld:%ld]'!\n", && (0 < physical_pb_port_ranges_[operating_pb_port].count(physical_pb_port)) ) {
operating_pb_port->name, port_range.get_lsb(), port_range.get_msb()); VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port range '%s[%ld:%ld]'!\n",
operating_pb_port->name,
physical_pb_port->name,
port_range.get_lsb(), port_range.get_msb());
} }
physical_pb_port_ranges_[operating_pb_port] = port_range; physical_pb_port_ranges_[operating_pb_port][physical_pb_port] = port_range;
} }
void VprDeviceAnnotation::add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model) { void VprDeviceAnnotation::add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model) {
@ -396,17 +424,34 @@ void VprDeviceAnnotation::add_physical_pb_type_index_offset(t_pb_type* pb_type,
physical_pb_type_index_offsets_[pb_type] = offset; physical_pb_type_index_offsets_[pb_type] = offset;
} }
void VprDeviceAnnotation::add_physical_pb_pin_rotate_offset(t_port* pb_port, const int& offset) { void VprDeviceAnnotation::add_physical_pb_pin_initial_offset(t_port* operating_pb_port,
t_port* physical_pb_port,
const int& offset) {
/* Warn any override attempt */ /* Warn any override attempt */
std::map<t_port*, int>::const_iterator it = physical_pb_pin_rotate_offsets_.find(pb_port); std::map<t_port*, std::map<t_port*, int>>::const_iterator it = physical_pb_pin_initial_offsets_.find(operating_pb_port);
if (it != physical_pb_pin_rotate_offsets_.end()) { if ( (it != physical_pb_pin_initial_offsets_.end())
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port pin rotate offset '%d'!\n", && (0 < physical_pb_pin_initial_offsets_[operating_pb_port].count(physical_pb_port)) ) {
pb_port->name, offset); VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port '%s' pin rotate offset '%d'!\n",
operating_pb_port->name, offset);
} }
physical_pb_pin_rotate_offsets_[pb_port] = offset; physical_pb_pin_initial_offsets_[operating_pb_port][physical_pb_port] = offset;
}
void VprDeviceAnnotation::add_physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port,
const int& offset) {
/* Warn any override attempt */
std::map<t_port*, std::map<t_port*, int>>::const_iterator it = physical_pb_pin_rotate_offsets_.find(operating_pb_port);
if ( (it != physical_pb_pin_rotate_offsets_.end())
&& (0 < physical_pb_pin_rotate_offsets_[operating_pb_port].count(physical_pb_port)) ) {
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port '%s' pin rotate offset '%d'!\n",
operating_pb_port->name, offset);
}
physical_pb_pin_rotate_offsets_[operating_pb_port][physical_pb_port] = offset;
/* We initialize the accumulated offset to 0 */ /* We initialize the accumulated offset to 0 */
physical_pb_pin_offsets_[pb_port] = 0; physical_pb_pin_offsets_[operating_pb_port][physical_pb_port] = 0;
} }
void VprDeviceAnnotation::add_physical_pb_graph_pin(const t_pb_graph_pin* operating_pb_graph_pin, void VprDeviceAnnotation::add_physical_pb_graph_pin(const t_pb_graph_pin* operating_pb_graph_pin,
@ -432,17 +477,17 @@ void VprDeviceAnnotation::add_physical_pb_graph_pin(const t_pb_graph_pin* operat
* Physical port | + + + * Physical port | + + +
* *
*/ */
if (0 == physical_pb_pin_rotate_offset(operating_pb_graph_pin->port)) { if (0 == physical_pb_pin_rotate_offset(operating_pb_graph_pin->port, physical_pb_graph_pin->port)) {
return; return;
} }
physical_pb_pin_offsets_[operating_pb_graph_pin->port] += physical_pb_pin_rotate_offset(operating_pb_graph_pin->port); physical_pb_pin_offsets_[operating_pb_graph_pin->port][physical_pb_graph_pin->port] += physical_pb_pin_rotate_offset(operating_pb_graph_pin->port, physical_pb_graph_pin->port);
if ((size_t)physical_pb_port(operating_pb_graph_pin->port)->num_pins - 1 if ((size_t)physical_pb_graph_pin->port->num_pins - 1
< operating_pb_graph_pin->pin_number < operating_pb_graph_pin->pin_number
+ physical_pb_port_range(operating_pb_graph_pin->port).get_lsb() + physical_pb_port_range(operating_pb_graph_pin->port, physical_pb_graph_pin->port).get_lsb()
+ physical_pb_pin_offsets_[operating_pb_graph_pin->port]) { + physical_pb_pin_offsets_[operating_pb_graph_pin->port][physical_pb_graph_pin->port]) {
physical_pb_pin_offsets_[operating_pb_graph_pin->port] = 0; physical_pb_pin_offsets_[operating_pb_graph_pin->port][physical_pb_graph_pin->port] = 0;
} }
} }

View File

@ -45,8 +45,9 @@ class VprDeviceAnnotation {
bool is_physical_pb_type(t_pb_type* pb_type) const; bool is_physical_pb_type(t_pb_type* pb_type) const;
t_mode* physical_mode(t_pb_type* pb_type) const; t_mode* physical_mode(t_pb_type* pb_type) const;
t_pb_type* physical_pb_type(t_pb_type* pb_type) const; t_pb_type* physical_pb_type(t_pb_type* pb_type) const;
t_port* physical_pb_port(t_port* pb_port) const; std::vector<t_port*> physical_pb_port(t_port* pb_port) const;
BasicPort physical_pb_port_range(t_port* pb_port) const; BasicPort physical_pb_port_range(t_port* operating_pb_port,
t_port* physical_pb_port) const;
CircuitModelId pb_type_circuit_model(t_pb_type* physical_pb_type) const; CircuitModelId pb_type_circuit_model(t_pb_type* physical_pb_type) const;
CircuitModelId interconnect_circuit_model(t_interconnect* pb_interconnect) const; CircuitModelId interconnect_circuit_model(t_interconnect* pb_interconnect) const;
e_interconnect interconnect_physical_type(t_interconnect* pb_interconnect) const; e_interconnect interconnect_physical_type(t_interconnect* pb_interconnect) const;
@ -60,7 +61,11 @@ class VprDeviceAnnotation {
float physical_pb_type_index_factor(t_pb_type* pb_type) const; float physical_pb_type_index_factor(t_pb_type* pb_type) const;
int physical_pb_type_index_offset(t_pb_type* pb_type) const; int physical_pb_type_index_offset(t_pb_type* pb_type) const;
int physical_pb_pin_rotate_offset(t_port* pb_port) const; int physical_pb_pin_initial_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const;
int physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const;
/**This function returns an accumulated offset. Note that the /**This function returns an accumulated offset. Note that the
* accumulated offset is NOT the pin rotate offset specified by users * accumulated offset is NOT the pin rotate offset specified by users
@ -69,7 +74,8 @@ class VprDeviceAnnotation {
* by the pin rotate offset value * by the pin rotate offset value
* The accumulated offset will be reset to 0 when it exceeds the msb() of the physical port * The accumulated offset will be reset to 0 when it exceeds the msb() of the physical port
*/ */
int physical_pb_pin_offset(t_port* pb_port) const; int physical_pb_pin_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const;
t_pb_graph_pin* physical_pb_graph_pin(const t_pb_graph_pin* pb_graph_pin) const; t_pb_graph_pin* physical_pb_graph_pin(const t_pb_graph_pin* pb_graph_pin) const;
CircuitModelId rr_switch_circuit_model(const RRSwitchId& rr_switch) const; CircuitModelId rr_switch_circuit_model(const RRSwitchId& rr_switch) const;
CircuitModelId rr_segment_circuit_model(const RRSegmentId& rr_segment) const; CircuitModelId rr_segment_circuit_model(const RRSegmentId& rr_segment) const;
@ -78,8 +84,11 @@ class VprDeviceAnnotation {
public: /* Public mutators */ public: /* Public mutators */
void add_pb_type_physical_mode(t_pb_type* pb_type, t_mode* physical_mode); void add_pb_type_physical_mode(t_pb_type* pb_type, t_mode* physical_mode);
void add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type); void add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type);
void add_physical_pb_port(t_port* operating_pb_port, t_port* physical_pb_port); void add_physical_pb_port(t_port* operating_pb_port,
void add_physical_pb_port_range(t_port* operating_pb_port, const BasicPort& port_range); t_port* physical_pb_port);
void add_physical_pb_port_range(t_port* operating_pb_port,
t_port* physical_pb_port,
const BasicPort& port_range);
void add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model); void add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model);
void add_interconnect_circuit_model(t_interconnect* pb_interconnect, const CircuitModelId& circuit_model); void add_interconnect_circuit_model(t_interconnect* pb_interconnect, const CircuitModelId& circuit_model);
void add_interconnect_physical_type(t_interconnect* pb_interconnect, const e_interconnect& physical_type); void add_interconnect_physical_type(t_interconnect* pb_interconnect, const e_interconnect& physical_type);
@ -90,7 +99,12 @@ class VprDeviceAnnotation {
t_pb_graph_node* physical_pb_graph_node); t_pb_graph_node* physical_pb_graph_node);
void add_physical_pb_type_index_factor(t_pb_type* pb_type, const float& factor); void add_physical_pb_type_index_factor(t_pb_type* pb_type, const float& factor);
void add_physical_pb_type_index_offset(t_pb_type* pb_type, const int& offset); void add_physical_pb_type_index_offset(t_pb_type* pb_type, const int& offset);
void add_physical_pb_pin_rotate_offset(t_port* pb_port, const int& offset); void add_physical_pb_pin_initial_offset(t_port* operating_pb_port,
t_port* physical_pb_port,
const int& offset);
void add_physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port,
const int& offset);
void add_physical_pb_graph_pin(const t_pb_graph_pin* operating_pb_graph_pin, t_pb_graph_pin* physical_pb_graph_pin); void add_physical_pb_graph_pin(const t_pb_graph_pin* operating_pb_graph_pin, t_pb_graph_pin* physical_pb_graph_pin);
void add_rr_switch_circuit_model(const RRSwitchId& rr_switch, const CircuitModelId& circuit_model); void add_rr_switch_circuit_model(const RRSwitchId& rr_switch, const CircuitModelId& circuit_model);
void add_rr_segment_circuit_model(const RRSegmentId& rr_segment, const CircuitModelId& circuit_model); void add_rr_segment_circuit_model(const RRSegmentId& rr_segment, const CircuitModelId& circuit_model);
@ -139,17 +153,18 @@ class VprDeviceAnnotation {
* Note: * Note:
* - the parent of physical pb_port MUST be a physical pb_type * - the parent of physical pb_port MUST be a physical pb_type
*/ */
std::map<t_port*, t_port*> physical_pb_ports_; std::map<t_port*, std::vector<t_port*>> physical_pb_ports_;
std::map<t_port*, int> physical_pb_pin_rotate_offsets_; std::map<t_port*, std::map<t_port*, int>> physical_pb_pin_initial_offsets_;
std::map<t_port*, std::map<t_port*, int>> physical_pb_pin_rotate_offsets_;
/* Accumulated offsets for a physical pb_type port, just for internal usage */ /* Accumulated offsets for a physical pb_type port, just for internal usage */
std::map<t_port*, int> physical_pb_pin_offsets_; std::map<t_port*, std::map<t_port*, int>> physical_pb_pin_offsets_;
/* Pair a pb_port to its LSB and MSB of a physical pb_port /* Pair a pb_port to its LSB and MSB of a physical pb_port
* Note: * Note:
* - the LSB and MSB MUST be in range of the physical pb_port * - the LSB and MSB MUST be in range of the physical pb_port
*/ */
std::map<t_port*, BasicPort> physical_pb_port_ranges_; std::map<t_port*, std::map<t_port*, BasicPort>> physical_pb_port_ranges_;
/* Pair a pb_port to a circuit port in circuit model /* Pair a pb_port to a circuit port in circuit model
* Note: * Note:

View File

@ -1,6 +1,6 @@
# Run VPR for the 'and' design # Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml #--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route --absorb_buffer_luts off
# Read OpenFPGA architecture definition # Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}

View File

@ -0,0 +1,371 @@
//-----------------------------------------------------
// Design Name : frac_mem_32k
// File Name : frac_mem_32k.v
// Function : A fracturable BRAM which can operate in 13 modes
// - Single port RAM 512x64 bit
// - Single port RAM 1024x32 bit
// - Single port RAM 2048x16 bit
// - Single port RAM 4096x8 bit
// - Single port RAM 8192x4 bit
// - Single port RAM 16384x2 bit
// - Single port RAM 32768x1 bit
// - Dual port RAM 1024x32
// - Dual port RAM 2048x16 bit
// - Dual port RAM 4096x8 bit
// - Dual port RAM 8192x4 bit
// - Dual port RAM 16384x2 bit
// - Dual port RAM 32768x1 bit
// Inspired by the dual port ram Verilog from
// https://www.intel.com/content/www/us/en/programmable/support/support-resources/design-examples/design-software/vhdl/vhd-true-dual-port-ram-sclk.html
// Coder : Xifan Tang
//-----------------------------------------------------
module frac_mem_32k (
input [0:14] addr_a,
input [0:14] addr_b,
input [0:31] data_a,
input [0:31] data_b,
input we_a,
input we_b,
output reg [0:31] q_a,
output reg [0:31] q_b,
input clk,
input [0:3] mode);
reg [0:9] ram_a [0:31];
reg [0:9] ram_b [0:31];
always @(posedge clk) begin
// Operating mode: single port RAM 512 x 64
if (4'b0000 == mode) begin
if (we_a) begin
ram_a[addr_a[0:8]] <= data_a;
ram_b[addr_a[0:8]] <= data_b;
q_a <= data_a;
q_b <= data_b;
end else begin
q_a <= ram_a[addr_a[0:8]];
q_b <= ram_b[addr_a[0:8]];
end
// Operating mode: single port RAM 1024 x 32
end else if (4'b0001 == mode) begin
if (we_a) begin
ram_a[addr_a[0:9]] <= data_a;
end else begin
q_a <= ram_a[addr_a[0:9]];
end
// Operating mode: single port RAM 2048 x 16
end else if (4'b0010 == mode) begin
if (we_a) begin
case (addr_a[10:10])
1'b0 : ram_a[addr_a[0:9]][0:15] <= data_a[0:15];
1'b1 : ram_a[addr_a[0:9]][16:31] <= data_a[0:15];
endcase
end else begin
case (addr_a[10:10])
1'b0 : q_a <= ram_a[addr_a[0:9]][0:15];
1'b1 : q_a <= ram_a[addr_a[0:9]][16:31];
endcase
end
// Operating mode: single port RAM 4096 x 8
end else if (4'b0011 == mode) begin
if (we_a) begin
case (addr_a[10:11])
2'b00 : ram_a[addr_a[0:9]][0:7] <= data_a[0:7];
2'b01 : ram_a[addr_a[0:9]][8:15] <= data_a[0:7];
2'b10 : ram_a[addr_a[0:9]][16:23] <= data_a[0:7];
2'b11 : ram_a[addr_a[0:9]][24:31] <= data_a[0:7];
endcase
end else begin
case (addr_a[10:11])
2'b00 : q_a <= ram_a[addr_a[0:9]][0:7];
2'b01 : q_a <= ram_a[addr_a[0:9]][8:15];
2'b10 : q_a <= ram_a[addr_a[0:9]][16:23];
2'b11 : q_a <= ram_a[addr_a[0:9]][24:31];
endcase
end
// Operating mode: single port RAM 8192 x 4
end else if (4'b0100 == mode) begin
if (we_a) begin
case (addr_a[10:12])
3'b000 : ram_a[addr_a[0:9]][0:3] <= data_a[0:3];
3'b001 : ram_a[addr_a[0:9]][4:7] <= data_a[0:3];
3'b010 : ram_a[addr_a[0:9]][8:11] <= data_a[0:3];
3'b011 : ram_a[addr_a[0:9]][12:15] <= data_a[0:3];
3'b100 : ram_a[addr_a[0:9]][16:19] <= data_a[0:3];
3'b101 : ram_a[addr_a[0:9]][20:23] <= data_a[0:3];
3'b110 : ram_a[addr_a[0:9]][24:27] <= data_a[0:3];
3'b111 : ram_a[addr_a[0:9]][28:31] <= data_a[0:3];
endcase
end else begin
case (addr_a[10:12])
3'b000 : q_a <= ram_a[addr_a[0:9]][0:3];
3'b001 : q_a <= ram_a[addr_a[0:9]][4:7];
3'b010 : q_a <= ram_a[addr_a[0:9]][8:11];
3'b011 : q_a <= ram_a[addr_a[0:9]][12:15];
3'b100 : q_a <= ram_a[addr_a[0:9]][16:19];
3'b101 : q_a <= ram_a[addr_a[0:9]][20:23];
3'b110 : q_a <= ram_a[addr_a[0:9]][24:27];
3'b111 : q_a <= ram_a[addr_a[0:9]][28:31];
endcase
end
// Operating mode: single port RAM 16384 x 2
end else if (4'b0101 == mode) begin
if (we_a) begin
case (addr_a[10:13])
4'b0000 : ram_a[addr_a[0:9]][0:1] <= data_a[0:1];
4'b0001 : ram_a[addr_a[0:9]][2:3] <= data_a[0:1];
4'b0010 : ram_a[addr_a[0:9]][4:5] <= data_a[0:1];
4'b0011 : ram_a[addr_a[0:9]][6:7] <= data_a[0:1];
4'b0100 : ram_a[addr_a[0:9]][8:9] <= data_a[0:1];
4'b0101 : ram_a[addr_a[0:9]][10:11] <= data_a[0:1];
4'b0110 : ram_a[addr_a[0:9]][12:13] <= data_a[0:1];
4'b0111 : ram_a[addr_a[0:9]][14:15] <= data_a[0:1];
4'b1000 : ram_a[addr_a[0:9]][16:17] <= data_a[0:1];
4'b1001 : ram_a[addr_a[0:9]][18:19] <= data_a[0:1];
4'b1010 : ram_a[addr_a[0:9]][20:21] <= data_a[0:1];
4'b1011 : ram_a[addr_a[0:9]][22:23] <= data_a[0:1];
4'b1100 : ram_a[addr_a[0:9]][24:25] <= data_a[0:1];
4'b1101 : ram_a[addr_a[0:9]][26:27] <= data_a[0:1];
4'b1110 : ram_a[addr_a[0:9]][28:29] <= data_a[0:1];
4'b1111 : ram_a[addr_a[0:9]][30:31] <= data_a[0:1];
endcase
end else begin
case (addr_a[10:13])
4'b0000 : q_a <= ram_a[addr_a[0:9]][0:1];
4'b0001 : q_a <= ram_a[addr_a[0:9]][2:3];
4'b0010 : q_a <= ram_a[addr_a[0:9]][4:5];
4'b0011 : q_a <= ram_a[addr_a[0:9]][6:7];
4'b0100 : q_a <= ram_a[addr_a[0:9]][8:9];
4'b0101 : q_a <= ram_a[addr_a[0:9]][10:11];
4'b0110 : q_a <= ram_a[addr_a[0:9]][12:13];
4'b0111 : q_a <= ram_a[addr_a[0:9]][14:15];
4'b1000 : q_a <= ram_a[addr_a[0:9]][16:17];
4'b1001 : q_a <= ram_a[addr_a[0:9]][18:19];
4'b1010 : q_a <= ram_a[addr_a[0:9]][20:21];
4'b1011 : q_a <= ram_a[addr_a[0:9]][22:23];
4'b1100 : q_a <= ram_a[addr_a[0:9]][24:25];
4'b1101 : q_a <= ram_a[addr_a[0:9]][26:27];
4'b1110 : q_a <= ram_a[addr_a[0:9]][28:29];
4'b1111 : q_a <= ram_a[addr_a[0:9]][30:31];
endcase
end
// Operating mode: single port RAM 32768 x 1
end else if (4'b0110 == mode) begin
if (we_a) begin
ram_a[addr_a[0:9]][addr_a[10:14]] = data_a[0:0];
end else begin
q_a <= ram_a[addr_a[0:9]][addr_a[10:14]];
end
// Operating mode: dual port RAM 1024 x 32
end else if (4'b0111 == mode) begin
if (we_a) begin
ram_a[addr_a[0:9]] <= data_a;
ram_b[addr_b[0:9]] <= data_b;
q_a <= data_a;
q_b <= data_b;
end else begin
q_a <= ram_a[addr_a[0:9]];
q_b <= ram_b[addr_b[0:9]];
end
// Operating mode: dual port RAM 2048 x 16
end else if (4'b1000 == mode) begin
if (we_a) begin
case (addr_a[10:10])
1'b0 : ram_a[addr_a[0:9]][0:15] <= data_a;
1'b1 : ram_a[addr_a[0:9]][16:31] <= data_a;
endcase
end else begin
case (addr_a[10:10])
1'b0 : q_a <= ram_a[addr_a[0:9]][0:15];
1'b1 : q_a <= ram_a[addr_a[0:9]][16:31];
endcase
end
if (we_b) begin
case (addr_b[10:10])
1'b0 : ram_b[addr_b[0:9]][0:15] <= data_b;
1'b1 : ram_b[addr_b[0:9]][16:31] <= data_b;
endcase
end else begin
case (addr_b[10:10])
1'b0 : q_b <= ram_b[addr_b[0:9]][0:15];
1'b1 : q_b <= ram_b[addr_b[0:9]][16:31];
endcase
end
// Operating mode: dual port RAM 4096 x 8
end else if (4'b1001 == mode) begin
if (we_a) begin
case (addr_a[10:11])
2'b00 : ram_a[addr_a[0:9]][0:7] <= data_a[0:7];
2'b01 : ram_a[addr_a[0:9]][8:15] <= data_a[0:7];
2'b10 : ram_a[addr_a[0:9]][16:23] <= data_a[0:7];
2'b11 : ram_a[addr_a[0:9]][24:31] <= data_a[0:7];
endcase
end else begin
case (addr_a[10:11])
2'b00 : q_a <= ram_a[addr_a[0:9]][0:7];
2'b01 : q_a <= ram_a[addr_a[0:9]][8:15];
2'b10 : q_a <= ram_a[addr_a[0:9]][16:23];
2'b11 : q_a <= ram_a[addr_a[0:9]][24:31];
endcase
end
if (we_b) begin
case (addr_b[10:11])
2'b00 : ram_b[addr_b[0:9]][0:7] <= data_b[0:7];
2'b01 : ram_b[addr_b[0:9]][8:15] <= data_b[0:7];
2'b10 : ram_b[addr_b[0:9]][16:23] <= data_b[0:7];
2'b11 : ram_b[addr_b[0:9]][24:31] <= data_b[0:7];
endcase
end else begin
case (addr_b[10:11])
2'b00 : q_b <= ram_b[addr_b[0:9]][0:7];
2'b01 : q_b <= ram_b[addr_b[0:9]][8:15];
2'b10 : q_b <= ram_b[addr_b[0:9]][16:23];
2'b11 : q_b <= ram_b[addr_b[0:9]][24:31];
endcase
end
// Operating mode: dual port RAM 8192 x 4
end else if (4'b1011 == mode) begin
if (we_a) begin
case (addr_a[10:12])
3'b000 : ram_a[addr_a[0:9]][0:3] <= data_a[0:3];
3'b001 : ram_a[addr_a[0:9]][4:7] <= data_a[0:3];
3'b010 : ram_a[addr_a[0:9]][8:11] <= data_a[0:3];
3'b011 : ram_a[addr_a[0:9]][12:15] <= data_a[0:3];
3'b100 : ram_a[addr_a[0:9]][16:19] <= data_a[0:3];
3'b101 : ram_a[addr_a[0:9]][20:23] <= data_a[0:3];
3'b110 : ram_a[addr_a[0:9]][24:27] <= data_a[0:3];
3'b111 : ram_a[addr_a[0:9]][28:31] <= data_a[0:3];
endcase
end else begin
case (addr_a[10:12])
3'b000 : q_a <= ram_a[addr_a[0:9]][0:3];
3'b001 : q_a <= ram_a[addr_a[0:9]][4:7];
3'b010 : q_a <= ram_a[addr_a[0:9]][8:11];
3'b011 : q_a <= ram_a[addr_a[0:9]][12:15];
3'b100 : q_a <= ram_a[addr_a[0:9]][16:19];
3'b101 : q_a <= ram_a[addr_a[0:9]][20:23];
3'b110 : q_a <= ram_a[addr_a[0:9]][24:27];
3'b111 : q_a <= ram_a[addr_a[0:9]][28:31];
endcase
end
if (we_b) begin
case (addr_b[10:12])
3'b000 : ram_b[addr_b[0:9]][0:3] <= data_b[0:3];
3'b001 : ram_b[addr_b[0:9]][4:7] <= data_b[0:3];
3'b010 : ram_b[addr_b[0:9]][8:11] <= data_b[0:3];
3'b011 : ram_b[addr_b[0:9]][12:15] <= data_b[0:3];
3'b100 : ram_b[addr_b[0:9]][16:19] <= data_b[0:3];
3'b101 : ram_b[addr_b[0:9]][20:23] <= data_b[0:3];
3'b110 : ram_b[addr_b[0:9]][24:27] <= data_b[0:3];
3'b111 : ram_b[addr_b[0:9]][28:31] <= data_b[0:3];
endcase
end else begin
case (addr_b[10:12])
3'b000 : q_b <= ram_b[addr_b[0:9]][0:3];
3'b001 : q_b <= ram_b[addr_b[0:9]][4:7];
3'b010 : q_b <= ram_b[addr_b[0:9]][8:11];
3'b011 : q_b <= ram_b[addr_b[0:9]][12:15];
3'b100 : q_b <= ram_b[addr_b[0:9]][16:19];
3'b101 : q_b <= ram_b[addr_b[0:9]][20:23];
3'b110 : q_b <= ram_b[addr_b[0:9]][24:27];
3'b111 : q_b <= ram_b[addr_b[0:9]][28:31];
endcase
end
// Operating mode: dual port RAM 16384 x 2
end else if (4'b1100 == mode) begin
if (we_a) begin
case (addr_a[10:13])
4'b0000 : ram_a[addr_a[0:9]][0:1] <= data_a[0:1];
4'b0001 : ram_a[addr_a[0:9]][2:3] <= data_a[0:1];
4'b0010 : ram_a[addr_a[0:9]][4:5] <= data_a[0:1];
4'b0011 : ram_a[addr_a[0:9]][6:7] <= data_a[0:1];
4'b0100 : ram_a[addr_a[0:9]][8:9] <= data_a[0:1];
4'b0101 : ram_a[addr_a[0:9]][10:11] <= data_a[0:1];
4'b0110 : ram_a[addr_a[0:9]][12:13] <= data_a[0:1];
4'b0111 : ram_a[addr_a[0:9]][14:15] <= data_a[0:1];
4'b1000 : ram_a[addr_a[0:9]][16:17] <= data_a[0:1];
4'b1001 : ram_a[addr_a[0:9]][18:19] <= data_a[0:1];
4'b1010 : ram_a[addr_a[0:9]][20:21] <= data_a[0:1];
4'b1011 : ram_a[addr_a[0:9]][22:23] <= data_a[0:1];
4'b1100 : ram_a[addr_a[0:9]][24:25] <= data_a[0:1];
4'b1101 : ram_a[addr_a[0:9]][26:27] <= data_a[0:1];
4'b1110 : ram_a[addr_a[0:9]][28:29] <= data_a[0:1];
4'b1111 : ram_a[addr_a[0:9]][30:31] <= data_a[0:1];
endcase
end else begin
case (addr_a[10:13])
4'b0000 : q_a <= ram_a[addr_a[0:9]][0:1];
4'b0001 : q_a <= ram_a[addr_a[0:9]][2:3];
4'b0010 : q_a <= ram_a[addr_a[0:9]][4:5];
4'b0011 : q_a <= ram_a[addr_a[0:9]][6:7];
4'b0100 : q_a <= ram_a[addr_a[0:9]][8:9];
4'b0101 : q_a <= ram_a[addr_a[0:9]][10:11];
4'b0110 : q_a <= ram_a[addr_a[0:9]][12:13];
4'b0111 : q_a <= ram_a[addr_a[0:9]][14:15];
4'b1000 : q_a <= ram_a[addr_a[0:9]][16:17];
4'b1001 : q_a <= ram_a[addr_a[0:9]][18:19];
4'b1010 : q_a <= ram_a[addr_a[0:9]][20:21];
4'b1011 : q_a <= ram_a[addr_a[0:9]][22:23];
4'b1100 : q_a <= ram_a[addr_a[0:9]][24:25];
4'b1101 : q_a <= ram_a[addr_a[0:9]][26:27];
4'b1110 : q_a <= ram_a[addr_a[0:9]][28:29];
4'b1111 : q_a <= ram_a[addr_a[0:9]][30:31];
endcase
end
if (we_b) begin
case (addr_b[10:13])
4'b0000 : ram_b[addr_b[0:9]][0:1] <= data_b[0:1];
4'b0001 : ram_b[addr_b[0:9]][2:3] <= data_b[0:1];
4'b0010 : ram_b[addr_b[0:9]][4:5] <= data_b[0:1];
4'b0011 : ram_b[addr_b[0:9]][6:7] <= data_b[0:1];
4'b0100 : ram_b[addr_b[0:9]][8:9] <= data_b[0:1];
4'b0101 : ram_b[addr_b[0:9]][10:11] <= data_b[0:1];
4'b0110 : ram_b[addr_b[0:9]][12:13] <= data_b[0:1];
4'b0111 : ram_b[addr_b[0:9]][14:15] <= data_b[0:1];
4'b1000 : ram_b[addr_b[0:9]][16:17] <= data_b[0:1];
4'b1001 : ram_b[addr_b[0:9]][18:19] <= data_b[0:1];
4'b1010 : ram_b[addr_b[0:9]][20:21] <= data_b[0:1];
4'b1011 : ram_b[addr_b[0:9]][22:23] <= data_b[0:1];
4'b1100 : ram_b[addr_b[0:9]][24:25] <= data_b[0:1];
4'b1101 : ram_b[addr_b[0:9]][26:27] <= data_b[0:1];
4'b1110 : ram_b[addr_b[0:9]][28:29] <= data_b[0:1];
4'b1111 : ram_b[addr_b[0:9]][30:31] <= data_b[0:1];
endcase
end else begin
case (addr_b[10:13])
4'b0000 : q_b <= ram_b[addr_b[0:9]][0:1];
4'b0001 : q_b <= ram_b[addr_b[0:9]][2:3];
4'b0010 : q_b <= ram_b[addr_b[0:9]][4:5];
4'b0011 : q_b <= ram_b[addr_b[0:9]][6:7];
4'b0100 : q_b <= ram_b[addr_b[0:9]][8:9];
4'b0101 : q_b <= ram_b[addr_b[0:9]][10:11];
4'b0110 : q_b <= ram_b[addr_b[0:9]][12:13];
4'b0111 : q_b <= ram_b[addr_b[0:9]][14:15];
4'b1000 : q_b <= ram_b[addr_b[0:9]][16:17];
4'b1001 : q_b <= ram_b[addr_b[0:9]][18:19];
4'b1010 : q_b <= ram_b[addr_b[0:9]][20:21];
4'b1011 : q_b <= ram_b[addr_b[0:9]][22:23];
4'b1100 : q_b <= ram_b[addr_b[0:9]][24:25];
4'b1101 : q_b <= ram_b[addr_b[0:9]][26:27];
4'b1110 : q_b <= ram_b[addr_b[0:9]][28:29];
4'b1111 : q_b <= ram_b[addr_b[0:9]][30:31];
endcase
end
// Operating mode: dual port RAM 32768 x 1
end else if (4'b1101 == mode) begin
if (we_a) begin
ram_a[addr_a[0:9]][addr_a[10:14]] = data_a[0:0];
end else begin
q_a <= ram_a[addr_a[0:9]][addr_a[10:14]];
end
if (we_b) begin
ram_b[addr_b[0:9]][addr_b[10:14]] = data_b[0:0];
end else begin
q_b <= ram_b[addr_b[0:9]][addr_b[10:14]];
end
end
end
endmodule

View File

@ -0,0 +1,35 @@
//-----------------------------------------------------
// Design Name : mult_36x36
// File Name : mult_36x36.v
// Function : A 36-bit multiplier which can operate in fracturable modes:
// 1. four 9-bit multipliers
// 2. two 18-bit multipliers
// 3. one 36-bit multipliers
// Coder : Xifan Tang
//-----------------------------------------------------
module mult_36x36 (
input [0:35] a,
input [0:35] b,
output [0:71] out,
input [0:1] mode);
reg [0:71] out_reg;
always @(mode, a, b) begin
if (2'b01 == mode) begin
out_reg[0:17] <= a[0:8] * b[0:8];
out_reg[18:35] <= a[9:17] * b[9:17];
out_reg[36:53] <= a[18:26] * b[18:26];
out_reg[54:71] <= a[27:35] * b[27:35];
end else if (2'b10 == mode) begin
out_reg[0:35] <= a[0:17] * b[0:17];
out_reg[36:71] <= a[18:35] * b[18:35];
end else begin
out_reg <= a * b;
end
end
assign out = out_reg;
endmodule

View File

@ -0,0 +1,439 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k6_N10_40nm.xml
- General purpose logic block
- K = 6, N = 10, I = 40
- Single mode
- Routing architecture
- L = 4, fc_in = 0.15, fc_out = 0.1
-->
<openfpga_architecture>
<technology_library>
<device_library>
<device_model name="logic" type="transistor">
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="0.9" pn_ratio="2"/>
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
</device_model>
<device_model name="io" type="transistor">
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="2.5" pn_ratio="3"/>
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
</device_model>
</device_library>
<variation_library>
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
</variation_library>
</technology_library>
<circuit_library>
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1" is_default="true">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="buf4" prefix="buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="tap_buf4" prefix="tap_buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="3" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="gate" name="OR2" prefix="OR2" is_default="true">
<design_technology type="cmos" topology="OR"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="a" size="1"/>
<port type="input" prefix="b" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="a b" out_port="out">
10e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="a b" out_port="out">
10e-12 5e-12
</delay_matrix>
</circuit_model>
<circuit_model type="pass_gate" name="TGATE" prefix="TGATE" is_default="true">
<design_technology type="cmos" topology="transmission_gate" nmos_size="1" pmos_size="2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="input" prefix="sel" size="1"/>
<port type="input" prefix="selb" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
</circuit_model>
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/> <!-- model_type could be T, res_val and cap_val DON'T CARE -->
</circuit_model>
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="0" C="0" num_level="1"/> <!-- model_type could be T, res_val cap_val should be defined -->
</circuit_model>
<circuit_model type="mux" name="mux_2level" prefix="mux_2level" dump_structural_verilog="true">
<design_technology type="cmos" structure="multi_level" num_level="2" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_2level_tapbuf" prefix="mux_2level_tapbuf" dump_structural_verilog="true">
<design_technology type="cmos" structure="multi_level" num_level="2" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_1level_tapbuf" prefix="mux_1level_tapbuf" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="one_level" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="static_dff" prefix="dff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="set" size="1" is_global="true" default_val="0" is_set="true"/>
<port type="input" prefix="reset" size="1" is_global="true" default_val="0" is_reset="true"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0" />
</circuit_model>
<circuit_model type="lut" name="frac_lut6" prefix="frac_lut6" dump_structural_verilog="true">
<design_technology type="cmos" fracturable_lut="true"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
<lut_intermediate_buffer exist="true" circuit_model_name="buf4" location_map="-1-1-"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="6" tri_state_map="----11" circuit_model_name="OR2"/>
<port type="output" prefix="lut4_out" size="4" lut_frac_level="4" lut_output_mask="0,1,2,3"/>
<port type="output" prefix="lut5_out" size="2" lut_frac_level="5" lut_output_mask="0,1"/>
<port type="output" prefix="lut6_out" size="1" lut_output_mask="0"/>
<port type="sram" prefix="sram" size="64"/>
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="ccff" name="sc_dff_compact" prefix="scff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="pReset" lib_name="reset" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="Qb" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="clk" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="iopad" prefix="iopad" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/io.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/io.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="inout" prefix="pad" size="1" is_global="true" is_io="true"/>
<port type="sram" prefix="en" size="1" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
<port type="input" prefix="outpad" size="1"/>
<port type="output" prefix="inpad" size="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="adder" prefix="adder" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/adder.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/adder.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="a" size="1"/>
<port type="input" prefix="b" size="1"/>
<port type="input" prefix="cin" size="1"/>
<port type="output" prefix="sumout" size="1"/>
<port type="output" prefix="cout" size="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="mult_36x36" prefix="mult_36x36" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/mult_36x36.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/mult_36x36.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="a" size="36"/>
<port type="input" prefix="b" size="36"/>
<port type="output" prefix="out" size="72"/>
<!-- As a fracturable multiplier, it requires 2 configuration bits to operate in 4 different modes -->
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="frac_mem_32k" prefix="frac_mem_32k" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/frac_mem_32k.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/frac_mem_32k.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="addr1" lib_name="addr_a" size="15"/>
<port type="input" prefix="addr2" lib_name="addr_b" size="15"/>
<port type="input" prefix="data1" lib_name="data_a" size="32"/>
<port type="input" prefix="data2" lib_name="data_b" size="32"/>
<port type="input" prefix="we1" lib_name="we_a" size="1"/>
<port type="input" prefix="we2" lib_name="we_b" size="1"/>
<port type="output" prefix="out1" lib_name="q_a" size="32"/>
<port type="output" prefix="out2" lib_name="q_b" size="32"/>
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0"/>
<!-- As a fracturable memory, it requires 4 configuration bits to operate in 13 different modes -->
<port type="sram" prefix="mode" size="4" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="sc_dff_compact"/>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_2level_tapbuf"/>
</connection_block>
<switch_block>
<switch name="0" circuit_model_name="mux_2level_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<direct_connection>
<direct name="adder_carry" circuit_model_name="direct_interc" type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<pb_type name="io[physical].iopad" circuit_model_name="iopad" mode_bits="1"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb">
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
<interconnect name="crossbar" circuit_model_name="mux_2level"/>
</pb_type>
<pb_type name="clb.fle" physical_mode_name="physical"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.frac_lut6" circuit_model_name="frac_lut6" mode_bits="11"/>
<pb_type name="clb.fle[physical].fabric.ff" circuit_model_name="static_dff"/>
<pb_type name="clb.fle[physical].fabric.adder" circuit_model_name="adder"/>
<!-- Binding operating pb_type to physical pb_type -->
<!-- Binding operating pb_types in mode 'n2_lut5' -->
<pb_type name="clb.fle[n2_lut5].ble5.lut5" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut6" mode_bits="01" physical_pb_type_index_factor="0.5">
<!-- Binding the lut5 to the first 5 inputs of fracturable lut6 -->
<port name="in" physical_mode_port="in[0:4]"/>
<port name="out" physical_mode_port="lut5_out[0:0]" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[n2_lut5].ble5.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- Binding operating pb_types in mode 'arithmetic' -->
<pb_type name="clb.fle[arithmetic].arithmetic.lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut6" mode_bits="11" physical_pb_type_index_factor="0.25">
<!-- Binding the lut4 to the first 4 inputs of fracturable lut6 -->
<port name="in" physical_mode_port="in[0:3]"/>
<port name="out" physical_mode_port="lut4_out[0:0]" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[arithmetic].arithmetic.adder" physical_pb_type_name="clb.fle[physical].fabric.adder"/>
<pb_type name="clb.fle[arithmetic].arithmetic.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- Binding operating pb_types in mode 'ble6' -->
<pb_type name="clb.fle[n1_lut6].ble6.lut6" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut6" mode_bits="00">
<!-- Binding the lut6 to the first 6 inputs of fracturable lut6 -->
<port name="in" physical_mode_port="in[0:5]"/>
<port name="out" physical_mode_port="lut6_out"/>
</pb_type>
<pb_type name="clb.fle[n1_lut6].ble6.ff" physical_pb_type_name="clb.fle[physical].fabric.ff" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0"/>
<!-- End physical pb_type binding in complex block clb -->
<!-- physical pb_type binding in complex block dsp -->
<pb_type name="mult_36" physical_mode_name="mult_36x36" idle_mode_name="mult_36x36"/>
<!-- Bind the primitive pb_type in the physical mode to a circuit model -->
<pb_type name="mult_36[mult_36x36].mult_36x36_slice.mult_36x36" circuit_model_name="mult_36x36" mode_bits="00"/>
<!-- Bind the 9x9 multiplier to the physical 36x36 multiplier
There are four 9x9 multipliers, each of which occupies part
of the input/output of the 36x36 multiplier
-->
<pb_type name="mult_36[two_divisible_mult_18x18].divisible_mult_18x18[two_mult_9x9].mult_9x9_slice.mult_9x9" physical_pb_type_name="mult_36[mult_36x36].mult_36x36_slice.mult_36x36" mode_bits="01" physical_pb_type_index_factor="0">
<port name="a" physical_mode_port="a[0:8]" physical_mode_pin_rotate_offset="9"/>
<port name="b" physical_mode_port="b[0:8]" physical_mode_pin_rotate_offset="9"/>
<port name="out" physical_mode_port="out[0:17]" physical_mode_pin_rotate_offset="18"/>
</pb_type>
<!-- Bind the 18x18 multiplier to the physical 36x36 multiplier
There are two 18x18 multipliers, each of which occupies part
of the input/output of the 36x36 multiplier
-->
<pb_type name="mult_36[two_divisible_mult_18x18].divisible_mult_18x18[mult_18x18].mult_18x18_slice.mult_18x18" physical_pb_type_name="mult_36[mult_36x36].mult_36x36_slice.mult_36x36" mode_bits="10" physical_pb_type_index_factor="0">
<port name="a" physical_mode_port="a[0:17]" physical_mode_pin_rotate_offset="18"/>
<port name="b" physical_mode_port="b[0:17]" physical_mode_pin_rotate_offset="18"/>
<port name="out" physical_mode_port="out[0:35]" physical_mode_pin_rotate_offset="36"/>
</pb_type>
<!-- END physical pb_type binding in complex block dsp -->
<!-- physical pb_type binding in complex block memory -->
<pb_type name="memory" physical_mode_name="physical" idle_mode_name="physical"/>
<pb_type name="memory[physical].frac_mem_32k" circuit_model_name="frac_mem_32k" mode_bits="0000"/>
<!-- Bind the 512x64 single port RAM to the physical implementation -->
<pb_type name="memory[mem_512x64_sp].mem_512x64_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0000">
<port name="addr" physical_mode_port="addr1[0:8]"/>
<port name="data" physical_mode_port="data1 data2" physical_mode_pin_initial_offset="-32 -32"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1 out2" physical_mode_pin_initial_offset="-32 -32"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 1024x32 single port RAM to the physical implementation -->
<pb_type name="memory[mem_1024x32_sp].mem_1024x32_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0001">
<port name="addr" physical_mode_port="addr1[0:9]"/>
<port name="data" physical_mode_port="data1"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 2048x16 single port RAM to the physical implementation -->
<pb_type name="memory[mem_2048x16_sp].mem_2048x16_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0010">
<port name="addr" physical_mode_port="addr1[0:10]"/>
<port name="data" physical_mode_port="data1[0:15]"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1[0:15]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 4096x8 single port RAM to the physical implementation -->
<pb_type name="memory[mem_4096x8_sp].mem_4096x8_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0011">
<port name="addr" physical_mode_port="addr1[0:11]"/>
<port name="data" physical_mode_port="data1[0:7]"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1[0:7]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 8192x4 single port RAM to the physical implementation -->
<pb_type name="memory[mem_8192x4_sp].mem_8192x4_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0100">
<port name="addr" physical_mode_port="addr1[0:12]"/>
<port name="data" physical_mode_port="data1[0:3]"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1[0:3]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 16384x2 single port RAM to the physical implementation -->
<pb_type name="memory[mem_16384x2_sp].mem_16384x2_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0101">
<port name="addr" physical_mode_port="addr1[0:13]"/>
<port name="data" physical_mode_port="data1[0:1]"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1[0:1]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 32768x1 single port RAM to the physical implementation -->
<pb_type name="memory[mem_32768x1_sp].mem_32768x1_sp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0110">
<port name="addr" physical_mode_port="addr1[0:14]"/>
<port name="data" physical_mode_port="data1[0:0]"/>
<port name="we" physical_mode_port="we1"/>
<port name="out" physical_mode_port="out1[0:0]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 1024x32 dual port RAM to the physical implementation -->
<pb_type name="memory[mem_1024x32_dp].mem_1024x32_dp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="0111">
<port name="addr1" physical_mode_port="addr1[0:9]"/>
<port name="addr2" physical_mode_port="addr2[0:9]"/>
<port name="data1" physical_mode_port="data1[0:31]"/>
<port name="data2" physical_mode_port="data2[0:31]"/>
<port name="we1" physical_mode_port="we1"/>
<port name="we2" physical_mode_port="we2"/>
<port name="out1" physical_mode_port="out1[0:31]"/>
<port name="out2" physical_mode_port="out2[0:31]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 2048x16 dual port RAM to the physical implementation -->
<pb_type name="memory[mem_2048x16_dp].mem_2048x16_dp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="1000">
<port name="addr1" physical_mode_port="addr1[0:10]"/>
<port name="addr2" physical_mode_port="addr2[0:10]"/>
<port name="data1" physical_mode_port="data1[0:15]"/>
<port name="data2" physical_mode_port="data2[0:15]"/>
<port name="we1" physical_mode_port="we1"/>
<port name="we2" physical_mode_port="we2"/>
<port name="out1" physical_mode_port="out1[0:15]"/>
<port name="out2" physical_mode_port="out2[0:15]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 4096x8 dual port RAM to the physical implementation -->
<pb_type name="memory[mem_4096x8_dp].mem_4096x8_dp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="1001">
<port name="addr1" physical_mode_port="addr1[0:11]"/>
<port name="addr2" physical_mode_port="addr2[0:11]"/>
<port name="data1" physical_mode_port="data1[0:7]"/>
<port name="data2" physical_mode_port="data2[0:7]"/>
<port name="we1" physical_mode_port="we1"/>
<port name="we2" physical_mode_port="we2"/>
<port name="out1" physical_mode_port="out1[0:7]"/>
<port name="out2" physical_mode_port="out2[0:7]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 8192x4 dual port RAM to the physical implementation -->
<pb_type name="memory[mem_8192x4_dp].mem_8192x4_dp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="1010">
<port name="addr1" physical_mode_port="addr1[0:12]"/>
<port name="addr2" physical_mode_port="addr2[0:12]"/>
<port name="data1" physical_mode_port="data1[0:3]"/>
<port name="data2" physical_mode_port="data2[0:3]"/>
<port name="we1" physical_mode_port="we1"/>
<port name="we2" physical_mode_port="we2"/>
<port name="out1" physical_mode_port="out1[0:3]"/>
<port name="out2" physical_mode_port="out2[0:3]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 16384x2 dual port RAM to the physical implementation -->
<pb_type name="memory[mem_16384x2_dp].mem_16384x2_dp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="1011">
<port name="addr1" physical_mode_port="addr1[0:13]"/>
<port name="addr2" physical_mode_port="addr2[0:13]"/>
<port name="data1" physical_mode_port="data1[0:1]"/>
<port name="data2" physical_mode_port="data2[0:1]"/>
<port name="we1" physical_mode_port="we1"/>
<port name="we2" physical_mode_port="we2"/>
<port name="out1" physical_mode_port="out1[0:1]"/>
<port name="out2" physical_mode_port="out2[0:1]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- Bind the 32768x1 dual port RAM to the physical implementation -->
<pb_type name="memory[mem_32768x1_dp].mem_32768x1_dp" physical_pb_type_name="memory[physical].frac_mem_32k" mode_bits="1100">
<port name="addr1" physical_mode_port="addr1[0:14]"/>
<port name="addr2" physical_mode_port="addr2[0:14]"/>
<port name="data1" physical_mode_port="data1[0:0]"/>
<port name="data2" physical_mode_port="data2[0:0]"/>
<port name="we1" physical_mode_port="we1"/>
<port name="we2" physical_mode_port="we2"/>
<port name="out1" physical_mode_port="out1[0:0]"/>
<port name="out2" physical_mode_port="out2[0:0]"/>
<port name="clk" physical_mode_port="clk"/>
</pb_type>
<!-- END physical pb_type binding in complex block memory -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -25,8 +25,9 @@ sub print_usage()
print " -i <input_blif_path>\n"; print " -i <input_blif_path>\n";
print " -o <output_blif_path>\n"; print " -o <output_blif_path>\n";
print " Options: (Optional)\n"; print " Options: (Optional)\n";
print " -remove_buffers\n"; print " -remove_buffers: remove buffers in the blif\n";
print " -add_default_clk\n"; print " -add_default_clk: add a default clock using the default clock name 'clk', or set by users through the option '-default clk'\n";
print " -default_clk <clk_name>: set the default clk name to be used by .latch\n";
print " -initial_blif <input_blif_path>\n"; print " -initial_blif <input_blif_path>\n";
print "\n"; print "\n";
return 0; return 0;
@ -46,6 +47,8 @@ sub opts_read()
$frpt = $ARGV[$iargv+1]; $frpt = $ARGV[$iargv+1];
} elsif ("-add_default_clk" eq $ARGV[$iargv]) { } elsif ("-add_default_clk" eq $ARGV[$iargv]) {
$add_default_clk = "on"; $add_default_clk = "on";
} elsif ("-default_clk" eq $ARGV[$iargv]) {
$default_clk_name = $ARGV[$iargv+1];
} elsif ("-initial_blif" eq $ARGV[$iargv]) { } elsif ("-initial_blif" eq $ARGV[$iargv]) {
$finitial = $ARGV[$iargv+1]; $finitial = $ARGV[$iargv+1];
} elsif ("-remove_buffers" eq $ARGV[$iargv]) { } elsif ("-remove_buffers" eq $ARGV[$iargv]) {
@ -219,7 +222,7 @@ sub scan_blif()
my ($line_no) = (0); my ($line_no) = (0);
if (!defined($finitial)) { if (!defined($finitial)) {
$latch_token = "re clk"; $latch_token = "re $default_clk_name";
} else { } else {
my $latch_token_found = 0; my $latch_token_found = 0;
my $count = 0; my $count = 0;

View File

@ -0,0 +1,36 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_thru_channel_adder_chain_mem16K_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -0,0 +1,36 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_thru_channel_adder_chain_wide_mem16K_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -1,17 +1,17 @@
# Naming convention for VPR architecture files # Naming convention for VPR architecture files
Please reveal the following architecture features in the names to help quickly spot architecture files. Please reveal the following architecture features in the names to help quickly spot architecture files.
- k<lut\_size>: Look-Up Table (LUT) size of FPGA. If you have fracturable LUTs or multiple LUT circuits, this should be largest input size. - k<lut\_size>\_<frac>: Look-Up Table (LUT) size of FPGA. If you have fracturable LUTs or multiple LUT circuits, this should be largest input size. The keyword 'frac' is to specify if fracturable LUT is used or not.
- frac: If fracturable LUT is used or not.
- N<le\_size>: Number of logic elements for a CLB. If you have multiple CLB architectures, this should be largest number. - N<le\_size>: Number of logic elements for a CLB. If you have multiple CLB architectures, this should be largest number.
- tileable: If the routing architecture is tileable or not. - tileable: If the routing architecture is tileable or not.
- adder\_chain: If hard adder/carry chain is used inside CLBs - adder\_chain: If hard adder/carry chain is used inside CLBs
- register\_chain: If shift register chain is used inside CLBs - register\_chain: If shift register chain is used inside CLBs
- scan\_chain: If scan chain testing infrastructure is used inside CLBs - scan\_chain: If scan chain testing infrastructure is used inside CLBs
- <wide>\_mem<mem\_size>: If block RAM (BRAM) is used or not. If used, the memory size should be clarified here. The keyword wide is to specify if the BRAM spanns more than 1 column. - <wide>\_<frac>\_mem<mem\_size>: If block RAM (BRAM) is used or not. If used, the memory size should be clarified here. The keyword 'wide' is to specify if the BRAM spans more than 1 column. The keyword 'frac' is to specify if the BRAM is fracturable to operate in different modes.
- <wide>\_<frac>\_dsp<dsp\_size>: If Digital Signal Processor (DSP) is used or not. If used, the input size should be clarified here. The keyword 'wide' is to specify if the DSP spans more than 1 column. The keyword 'frac' is to specify if the DSP is fracturable to operate in different modes.
- aib: If the Advanced Interface Bus (AIB) is used in place of some I/Os. - aib: If the Advanced Interface Bus (AIB) is used in place of some I/Os.
- multi\_io\_capacity: If I/O capacity is different on each side of FPGAs. - multi\_io\_capacity: If I/O capacity is different on each side of FPGAs.
- reduced\_io: If I/Os only appear a certain or multiple sides of FPGAs - reduced\_io: If I/Os only appear a certain or multiple sides of FPGAs
- <feature_size>: The technology node which the delay numbers are extracted from. - <feature\_size>: The technology node which the delay numbers are extracted from.
Other features are used in naming should be listed here. Other features are used in naming should be listed here.

View File

@ -188,7 +188,7 @@
<output name="d_out" num_pins="32"/> <output name="d_out" num_pins="32"/>
<clock name="clk" num_pins="1"/> <clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/> <fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="spread"/> <pinlocations pattern="perimeter"/>
</tile> </tile>
</tiles> </tiles>
<!-- ODIN II specific config ends --> <!-- ODIN II specific config ends -->

View File

@ -188,7 +188,14 @@
<output name="d_out" num_pins="32"/> <output name="d_out" num_pins="32"/>
<clock name="clk" num_pins="1"/> <clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/> <fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="spread"/> <pinlocations pattern="perimeter"/>
<!--pinlocations pattern="custom">
<loc side="left"></loc>
<loc side="top">memory.clk</loc>
<loc side="right" yoffset="0">memory.waddr[0:4] memory.d_in[0:15] memory.wen</loc>
<loc side="right" yoffset="1">memory.raddr[0:4] memory.d_out[0:15]</loc>
<loc side="bottom">memory.waddr[5:9] memory.raddr[5:9] memory.d_in[16:31] memory.ren memory.d_out[16:31]</loc>
</pinlocations-->
</tile> </tile>
</tiles> </tiles>
<!-- ODIN II specific config ends --> <!-- ODIN II specific config ends -->

View File

@ -0,0 +1,734 @@
<!--
Flagship Heterogeneous Architecture with Carry Chains for VTR 7.0.
- 40 nm technology
- General purpose logic block:
K = 6, N = 10, fracturable 6 LUTs (can operate as one 6-LUT or two 5-LUTs with 8 total FLE inputs (2 inputs of which are shared by the 5-LUTs)
with optionally registered outputs
Each 5-LUT has an arithemtic mode that converts it to a single-bit adder with both inputs driven by 4-LUTs (both 4-LUTs share all 4 inputs)
Carry chain links to vertically adjacent logic blocks
- Memory size 32 Kbits, memory aspect ratios vary from a data width of 1 to data width of 64.
Height = 6, found on every (8n+2)th column
- Multiplier modes: one 36x36, two 18x18, each 18x18 can also operate as two 9x9.
Height = 4, found on every (8n+6)th column
- Routing architecture: L = 4, fc_in = 0.15, Fc_out = 0.1
Details on Modelling:
The electrical design of the architecture described here is NOT from an
optimized, SPICED architecture. Instead, we attempt to create a reasonable
architecture file by using an existing commercial FPGA to approximate the area,
delay, and power of the underlying components. This is combined with a reasonable 40 nm
model of wiring and circuit design for low-level routing components, where available.
The resulting architecture has delays that roughly match a commercial 40 nm FPGA, but also
has wiring electrical parameters that allow the wire lengths and switch patterns to be
modified and you will still get reasonable delay results for the new architecture.
The following describes, in detail, how we obtained the various electrical values for this
architecture.
Rmin for nmos and pmos, routing buffer sizes, and I/O pad delays are from the ifar
architecture created by Ian Kuon: K06 N10 45nm fc 0.15 area-delay optimized architecture.
(n10k06l04.fc15.area1delay1.cmos45nm.bptm.cmos45nm.xml)
This routing architecture was optimized for 45 nm, and we have scaled it linearly to 40 nm to
match the overall target (a 40 nm FPGA).
We obtain delay numbers by measuring delays of routing, soft logic blocks,
memories, and multipliers from test circuits on a Stratix IV GX device
(EP4SGX230DF29C2X, i.e. fastest speed grade). For routing, we took the average delay of H4 and V4
wires. Rmetal and Cmetal values for the routing wires were obtained from work done by Charles
Chiasson. We use a 96 nm half-pitch (corresponding to mid-level metal stack 40 nm routing) and
take the R and C data from the ITRS roadmap.
For the general purpose logic block, we assume that the area and delays of the Stratix IV
crossbar is close enough to the crossbar modelled here.
Stratix IV uses 52 inputs and 20 feedback lines, but only a half-populated crossbar, leading to
36:1 multiplexers. We match these parameters in this architecture.
For LUTs, we include LUT
delays measured from Stratix IV which is dependant on the input used (ie. some
LUT inputs are faster than others). The CAD tools at the time of VTR 7 does
not consider differences in LUT input delays.
Adder delays obtained as approximate values from a Stratix IV EP4SE230F29C3 device.
Delay obtained by compiling a 256 bit adder (registered inputs and outputs,
all pins except clock virtual) then measuring the delays in chip-planner,
sumout delay = 0.271ns to 0.348 ns, intra-block carry delay = 0.011 ns,
inter-block carry delay = 0.327 ns. Given this data, I will approximate
sumout 0.3 ns, intra-block carry-delay = 0.01 ns, and
inter-block carry-delay = 0.16 ns (since Altera inter-block carry delay has
overhead that we don't have, I'll approximate the delay of a simpler chain at
one half what they have. This is very rough, anything from 0.01ns to 0.327ns
can be justified).
Logic block area numbers obtained by scaling overall tile area of a 65nm
Stratix III device, (as given in Wong, Betz and Rose, FPGA 2011) to 40 nm, then subtracting out
routing area at a channel width of 300. We use a channel width of 300 because it can route
all the VTR 6.0 benchmark circuits with an approximately 20% safety margin, and is also close to the
total channel width of Stratix IV. Hence this channel width is close to the commercial practice of
choosing a width that provides high routability. The architecture can be routed at different channel
widths, but we estimate the tile size and hence the physical length of routing wires assuming
a channel width of 300.
Sanity checks employed:
1. We confirmed the routing buffer delay is ~1/3rd of total routing delay at L = 4. This matches
common electrical design.
Authors: Jason Luu, Jeff Goeders, Vaughn Betz
-->
<architecture>
<!--
ODIN II specific config begins
Describes the types of user-specified netlist blocks (in blif, this corresponds to
".model [type_of_block]") that this architecture supports.
Note: Basic LUTs, I/Os, and flip-flops are not included here as there are
already special structures in blif (.names, .input, .output, and .latch)
that describe them.
-->
<models>
<model name="adder">
<input_ports>
<port name="a" combinational_sink_ports="sumout cout"/>
<port name="b" combinational_sink_ports="sumout cout"/>
<port name="cin" combinational_sink_ports="sumout cout"/>
</input_ports>
<output_ports>
<port name="cout"/>
<port name="sumout"/>
</output_ports>
</model>
<!-- A virtual model for I/O to be used in the physical mode of io block -->
<model name="io">
<input_ports>
<port name="outpad"/>
</input_ports>
<output_ports>
<port name="inpad"/>
</output_ports>
</model>
<!-- A virtual model for I/O to be used in the physical mode of io block -->
<model name="frac_lut6">
<input_ports>
<port name="in"/>
</input_ports>
<output_ports>
<port name="lut4_out"/>
<port name="lut5_out"/>
<port name="lut6_out"/>
</output_ports>
</model>
<model name="dual_port_ram">
<input_ports>
<!-- write address lines -->
<port name="waddr" clock="clk"/>
<!-- read address lines -->
<port name="raddr" clock="clk"/>
<!-- data lines can be broken down into smaller bit widths minimum size 1 -->
<port name="d_in" clock="clk"/>
<!-- write enable -->
<port name="wen" clock="clk"/>
<!-- read enable -->
<port name="ren" clock="clk"/>
<!-- memories are often clocked -->
<port name="clk" is_clock="1"/>
</input_ports>
<output_ports>
<!-- output can be broken down into smaller bit widths minimum size 1 -->
<port name="d_out" clock="clk"/>
</output_ports>
</model>
</models>
<tiles>
<tile name="io" capacity="8" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="left">io.outpad io.inpad</loc>
<loc side="top">io.outpad io.inpad</loc>
<loc side="right">io.outpad io.inpad</loc>
<loc side="bottom">io.outpad io.inpad</loc>
</pinlocations>
</tile>
<tile name="clb" area="53894">
<equivalent_sites>
<site pb_type="clb"/>
</equivalent_sites>
<input name="I" num_pins="40" equivalent="full"/>
<input name="cin" num_pins="1"/>
<output name="O" num_pins="20" equivalent="none"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
<fc_override port_name="cin" fc_type="frac" fc_val="0"/>
<fc_override port_name="cout" fc_type="frac" fc_val="0"/>
</fc>
<!-- Highly recommand to customize pin location when direct connection is used!!! -->
<!--pinlocations pattern="spread"/-->
<pinlocations pattern="custom">
<loc side="left">clb.clk</loc>
<loc side="top">clb.cin</loc>
<loc side="right">clb.O[9:0] clb.I[19:0]</loc>
<loc side="bottom">clb.cout clb.O[19:10] clb.I[39:20]</loc>
</pinlocations>
</tile>
<tile name="memory" width="2" height="2" area="548000">
<equivalent_sites>
<site pb_type="memory"/>
</equivalent_sites>
<input name="waddr" num_pins="10"/>
<input name="raddr" num_pins="10"/>
<input name="d_in" num_pins="32"/>
<input name="wen" num_pins="1"/>
<input name="ren" num_pins="1"/>
<output name="d_out" num_pins="32"/>
<clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="perimeter"/>
</tile>
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout tileable="true" through_channel="true">
<!--auto_layout aspect_ratio="1.0"-->
<fixed_layout name="4x4" width="6" height="6">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<perimeter type="io" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
<!--Column of 'memory' with 'EMPTY' blocks wherever a 'memory' does not fit. Vertical offset by 1 for perimeter.-->
<col type="memory" startx="2" starty="1" repeatx="8" priority="20"/>
<col type="EMPTY" startx="2" repeatx="8" starty="1" priority="19"/>
</fixed_layout>
<!-- /auto_layout -->
</layout>
<device>
<!-- VB & JL: Using Ian Kuon's transistor sizing and drive strength data for routing, at 40 nm. Ian used BPTM
models. We are modifying the delay values however, to include metal C and R, which allows more architecture
experimentation. We are also modifying the relative resistance of PMOS to be 1.8x that of NMOS
(vs. Ian's 3x) as 1.8x lines up with Jeff G's data from a 45 nm process (and is more typical of
45 nm in general). I'm upping the Rmin_nmos from Ian's just over 6k to nearly 9k, and dropping
RminW_pmos from 18k to 16k to hit this 1.8x ratio, while keeping the delays of buffers approximately
lined up with Stratix IV.
We are using Jeff G.'s capacitance data for 45 nm (in tech/ptm_45nm).
Jeff's tables list C in for transistors with widths in multiples of the minimum feature size (45 nm).
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply drive strength sizes in this file
by 2.5x when looking up in Jeff's tables.
The delay values are lined up with Stratix IV, which has an architecture similar to this
proposed FPGA, and which is also 40 nm
C_ipin_cblock: input capacitance of a track buffer, which VPR assumes is a single-stage
4x minimum drive strength buffer. -->
<sizing R_minW_nmos="8926" R_minW_pmos="16067"/>
<!-- The grid_logic_tile_area below will be used for all blocks that do not explicitly set their own (non-routing)
area; set to 0 since we explicitly set the area of all blocks currently in this architecture file.
-->
<area grid_logic_tile_area="0"/>
<chan_width_distr>
<x distr="uniform" peak="1.000000"/>
<y distr="uniform" peak="1.000000"/>
</chan_width_distr>
<switch_block type="wilton" fs="3"/>
<connection_block input_switch_name="ipin_cblock"/>
</device>
<switchlist>
<!-- VB: the mux_trans_size and buf_size data below is in minimum width transistor *areas*, assuming the purple
book area formula. This means the mux transistors are about 5x minimum drive strength.
We assume the first stage of the buffer is 3x min drive strength to be reasonable given the large
mux transistors, and this gives a reasonable stage ratio of a bit over 5x to the second stage. We assume
the n and p transistors in the first stage are equal-sized to lower the buffer trip point, since it's fed
by a pass transistor mux. We can then reverse engineer the buffer second stage to hit the specified
buf_size (really buffer area) - 16.2x minimum drive nmos and 1.8*16.2 = 29.2x minimum drive.
I then took the data from Jeff G.'s PTM modeling of 45 nm to get the Cin (gate of first stage) and Cout
(diff of second stage) listed below. Jeff's models are in tech/ptm_45nm, and are in min feature multiples.
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply the drive strength sizes above by
2.5x when looking up in Jeff's tables.
Finally, we choose a switch delay (58 ps) that leads to length 4 wires having a delay equal to that of SIV of 126 ps.
This also leads to the switch being 46% of the total wire delay, which is reasonable. -->
<switch type="mux" name="0" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<!--switch ipin_cblock resistance set to yeild for 4x minimum drive strength buffer-->
<switch type="mux" name="ipin_cblock" R="2231.5" Cout="0." Cin="1.47e-15" Tdel="7.247000e-11" mux_trans_size="1.222260" buf_size="auto"/>
</switchlist>
<segmentlist>
<!--- VB & JL: using ITRS metal stack data, 96 nm half pitch wires, which are intermediate metal width/space.
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
<!-- GIVE a specific name for the segment! OpenFPGA appreciate that! -->
<segment name="L4" freq="1.000000" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="0"/>
<sb type="pattern">1 1 1 1 1</sb>
<cb type="pattern">1 1 1 1</cb>
</segment>
</segmentlist>
<directlist>
<direct name="adder_carry" from_pin="clb.cout" to_pin="clb.cin" x_offset="0" y_offset="-1" z_offset="0"/>
</directlist>
<complexblocklist>
<!-- Define I/O pads begin -->
<!-- Capacity is a unique property of I/Os, it is the maximum number of I/Os that can be placed at the same (X,Y) location on the FPGA -->
<!-- Not sure of the area of an I/O (varies widely), and it's not relevant to the design of the FPGA core, so we're setting it to 0. -->
<pb_type name="io">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<!-- Do NOT add clock pins to I/O here!!! VPR does not build clock network in the way that OpenFPGA can support
If you need to register the I/O, define clocks in the circuit models
These clocks can be handled in back-end
-->
<!-- A mode denotes the physical implementation of an I/O
This mode will be not packable but is mainly used for fabric verilog generation
-->
<mode name="physical" disabled_in_pack="true">
<pb_type name="iopad" blif_model=".subckt io" num_pb="1">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="iopad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="iopad.outpad"/>
</direct>
<direct name="inpad" input="iopad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="iopad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<!-- IOs can operate as either inputs or outputs.
Delays below come from Ian Kuon. They are small, so they should be interpreted as
the delays to and from registers in the I/O (and generally I/Os are registered
today and that is when you timing analyze them.
-->
<mode name="inpad">
<pb_type name="inpad" blif_model=".input" num_pb="1">
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="inpad" input="inpad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="inpad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<mode name="outpad">
<pb_type name="outpad" blif_model=".output" num_pb="1">
<input name="outpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="outpad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="outpad.outpad"/>
</direct>
</interconnect>
</mode>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- IOs go on the periphery of the FPGA, for consistency,
make it physically equivalent on all sides so that only one definition of I/Os is needed.
If I do not make a physically equivalent definition, then I need to define 4 different I/Os, one for each side of the FPGA
-->
<!-- Place I/Os on the sides of the FPGA -->
<power method="ignore"/>
</pb_type>
<!-- Define I/O pads ends -->
<!-- Define general purpose logic block (CLB) begin -->
<!--- Area calculation: Total Stratix IV tile area is about 8100 um^2, and a minimum width transistor
area is 60 L^2 yields a tile area of 84375 MWTAs.
Routing at W=300 is 30481 MWTAs, leaving us with a total of 53000 MWTAs for logic block area
This means that only 37% of our area is in the general routing, and 63% is inside the logic
block. Note that the crossbar / local interconnect is considered part of the logic block
area in this analysis. That is a lower proportion of of routing area than most academics
assume, but note that the total routing area really includes the crossbar, which would push
routing area up significantly, we estimate into the ~70% range.
-->
<pb_type name="clb">
<input name="I" num_pins="40" equivalent="full"/>
<input name="cin" num_pins="1"/>
<output name="O" num_pins="20" equivalent="none"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Describe fracturable logic element.
Each fracturable logic element has a 6-LUT that can alternatively operate as two 5-LUTs with shared inputs.
The outputs of the fracturable logic element can be optionally registered
-->
<pb_type name="fle" num_pb="10">
<input name="in" num_pins="6"/>
<input name="cin" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Physical mode definition begin (physical implementation of the fle) -->
<mode name="physical" disabled_in_pack="true">
<pb_type name="fabric" num_pb="1">
<input name="in" num_pins="6"/>
<input name="cin" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<pb_type name="frac_logic" num_pb="1">
<input name="in" num_pins="6"/>
<output name="lut4_out" num_pins="4"/>
<output name="out" num_pins="2"/>
<!-- Define LUT -->
<pb_type name="frac_lut6" blif_model=".subckt frac_lut6" num_pb="1">
<input name="in" num_pins="6"/>
<output name="lut4_out" num_pins="4"/>
<output name="lut5_out" num_pins="2"/>
<output name="lut6_out" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="direct1" input="frac_logic.in" output="frac_lut6.in"/>
<direct name="direct2" input="frac_lut6.lut4_out" output="frac_logic.lut4_out"/>
<direct name="direct3" input="frac_lut6.lut5_out[1]" output="frac_logic.out[1]"/>
<!-- Xifan Tang: I use out[0] because the output of lut6 in lut6 mode is wired to the out[0] -->
<mux name="mux1" input="frac_lut6.lut6_out frac_lut6.lut5_out[0]" output="frac_logic.out[0]"/>
</interconnect>
</pb_type>
<!-- Define flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="2" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<!-- Define adders -->
<pb_type name="adder" blif_model=".subckt adder" num_pb="2">
<input name="a" num_pins="1"/>
<input name="b" num_pins="1"/>
<input name="cin" num_pins="1"/>
<output name="cout" num_pins="1"/>
<output name="sumout" num_pins="1"/>
<delay_constant max="0.3e-9" in_port="adder.a" out_port="adder.sumout"/>
<delay_constant max="0.3e-9" in_port="adder.b" out_port="adder.sumout"/>
<delay_constant max="0.3e-9" in_port="adder.cin" out_port="adder.sumout"/>
<delay_constant max="0.3e-9" in_port="adder.a" out_port="adder.cout"/>
<delay_constant max="0.3e-9" in_port="adder.b" out_port="adder.cout"/>
<delay_constant max="0.01e-9" in_port="adder.cin" out_port="adder.cout"/>
</pb_type>
<interconnect>
<direct name="direct1" input="fabric.in" output="frac_logic.in"/>
<direct name="direct2" input="frac_logic.out[1:0]" output="ff[1:0].D"/>
<direct name="direct3" input="fabric.cin" output="adder[0:0].cin"/>
<direct name="direct4" input="adder[0:0].cout" output="adder[1:1].cin"/>
<direct name="direct5" input="adder[1:1].cout" output="fabric.cout"/>
<direct name="direct6" input="frac_logic.lut4_out[0:0]" output="adder[0:0].a"/>
<direct name="direct7" input="frac_logic.lut4_out[1:1]" output="adder[0:0].b"/>
<direct name="direct8" input="frac_logic.lut4_out[2:2]" output="adder[1:1].a"/>
<direct name="direct9" input="frac_logic.lut4_out[3:3]" output="adder[1:1].b"/>
<complete name="direct10" input="fabric.clk" output="ff[1:0].clk"/>
<mux name="mux1" input="adder[0].sumout ff[0].Q frac_logic.out[0]" output="fabric.out[0]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="frac_logic.out[0]" out_port="fabric.out[0]"/>
<delay_constant max="45e-12" in_port="ff[0].Q" out_port="fabric.out[0]"/>
</mux>
<mux name="mux2" input="adder[1].sumout ff[1].Q frac_logic.out[1]" output="fabric.out[1]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="frac_logic.out[1]" out_port="fabric.out[1]"/>
<delay_constant max="45e-12" in_port="ff[1].Q" out_port="fabric.out[1]"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="fabric.in"/>
<direct name="direct2" input="fle.cin" output="fabric.cin"/>
<direct name="direct3" input="fabric.out" output="fle.out"/>
<direct name="direct4" input="fabric.cout" output="fle.cout"/>
<direct name="direct5" input="fle.clk" output="fabric.clk"/>
</interconnect>
</mode>
<!-- Physical mode definition end (physical implementation of the fle) -->
<!-- BEGIN fle mode of dual lut5 -->
<mode name="n2_lut5">
<pb_type name="ble5" num_pb="2">
<input name="in" num_pins="5"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Regular LUT mode -->
<pb_type name="lut5" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="5" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
398e-12
-->
<delay_matrix type="max" in_port="lut5.in" out_port="lut5.out">
235e-12
235e-12
235e-12
235e-12
235e-12
</delay_matrix>
</pb_type>
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble5.in" output="lut5.in"/>
<direct name="direct2" input="lut5.out" output="ff.D">
<pack_pattern name="ble5" in_port="lut5.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble5.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut5.out" output="ble5.out">
<delay_constant max="25e-12" in_port="lut5.out" out_port="ble5.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble5.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in[4:0]" output="ble5[0:0].in"/>
<direct name="direct2" input="fle.in[4:0]" output="ble5[1:1].in"/>
<complete name="direct3" input="fle.clk" output="ble5.clk"/>
<direct name="direct4" input="ble5.out" output="fle.out"/>
</interconnect>
</mode>
<!-- END fle mode of dual lut5 -->
<!-- BEGIN arithmetic mode of dual lut4 + adders -->
<mode name="arithmetic">
<pb_type name="arithmetic" num_pb="2">
<input name="in" num_pins="4"/>
<input name="cin" num_pins="1"/>
<output name="out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Special dual-LUT mode that drives adder only -->
<pb_type name="lut4" blif_model=".names" num_pb="2" class="lut">
<input name="in" num_pins="4" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
-->
<delay_matrix type="max" in_port="lut4.in" out_port="lut4.out">
195e-12
195e-12
195e-12
195e-12
</delay_matrix>
</pb_type>
<pb_type name="adder" blif_model=".subckt adder" num_pb="1">
<input name="a" num_pins="1"/>
<input name="b" num_pins="1"/>
<input name="cin" num_pins="1"/>
<output name="cout" num_pins="1"/>
<output name="sumout" num_pins="1"/>
<delay_constant max="0.3e-9" in_port="adder.a" out_port="adder.sumout"/>
<delay_constant max="0.3e-9" in_port="adder.b" out_port="adder.sumout"/>
<delay_constant max="0.3e-9" in_port="adder.cin" out_port="adder.sumout"/>
<delay_constant max="0.3e-9" in_port="adder.a" out_port="adder.cout"/>
<delay_constant max="0.3e-9" in_port="adder.b" out_port="adder.cout"/>
<delay_constant max="0.01e-9" in_port="adder.cin" out_port="adder.cout"/>
</pb_type>
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="clock" input="arithmetic.clk" output="ff.clk"/>
<direct name="lut_in1" input="arithmetic.in[3:0]" output="lut4[0:0].in[3:0]"/>
<direct name="lut_in2" input="arithmetic.in[3:0]" output="lut4[1:1].in[3:0]"/>
<direct name="lut_to_add1" input="lut4[0:0].out" output="adder.a">
</direct>
<direct name="lut_to_add2" input="lut4[1:1].out" output="adder.b">
</direct>
<direct name="add_to_ff" input="adder.sumout" output="ff.D">
<pack_pattern name="chain" in_port="adder.sumout" out_port="ff.D"/>
</direct>
<direct name="carry_in" input="arithmetic.cin" output="adder.cin">
<pack_pattern name="chain" in_port="arithmetic.cin" out_port="adder.cin"/>
</direct>
<direct name="carry_out" input="adder.cout" output="arithmetic.cout">
<pack_pattern name="chain" in_port="adder.cout" out_port="arithmetic.cout"/>
</direct>
<mux name="sumout" input="ff.Q adder.sumout" output="arithmetic.out">
<delay_constant max="25e-12" in_port="adder.sumout" out_port="arithmetic.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="arithmetic.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in[3:0]" output="arithmetic[0:0].in"/>
<direct name="direct2" input="fle.in[3:0]" output="arithmetic[1:1].in"/>
<direct name="carry_in" input="fle.cin" output="arithmetic[0:0].cin">
<pack_pattern name="chain" in_port="fle.cin" out_port="arithmetic[0:0].cin"/>
</direct>
<direct name="carry_inter" input="arithmetic[0:0].cout" output="arithmetic[1:1].cin">
<pack_pattern name="chain" in_port="arithmetic[0:0].cout" out_port="arithmetic[1:1].cin"/>
</direct>
<direct name="carry_out" input="arithmetic[1:1].cout" output="fle.cout">
<pack_pattern name="chain" in_port="arithmetic.cout" out_port="fle.cout"/>
</direct>
<complete name="direct3" input="fle.clk" output="arithmetic.clk"/>
<direct name="direct4" input="arithmetic.out" output="fle.out"/>
</interconnect>
</mode>
<!-- n2_lut5 -->
<mode name="n1_lut6">
<pb_type name="ble6" num_pb="1">
<input name="in" num_pins="6"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<pb_type name="lut6" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="6" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
398e-12
397e-12
-->
<delay_matrix type="max" in_port="lut6.in" out_port="lut6.out">
261e-12
261e-12
261e-12
261e-12
261e-12
261e-12
</delay_matrix>
</pb_type>
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble6.in" output="lut6[0:0].in"/>
<direct name="direct2" input="lut6.out" output="ff.D">
<pack_pattern name="ble6" in_port="lut6.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble6.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut6.out" output="ble6.out">
<delay_constant max="25e-12" in_port="lut6.out" out_port="ble6.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble6.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in[5:0]" output="ble6.in"/>
<direct name="direct2" input="ble6.out" output="fle.out[0:0]"/>
<direct name="direct3" input="fle.clk" output="ble6.clk"/>
</interconnect>
</mode>
<!-- n1_lut6 -->
</pb_type>
<interconnect>
<!-- We use a 50% depop crossbar built using small full xbars to get sets of logically equivalent pins at inputs of CLB
The delays below come from Stratix IV. the delay through a connection block
input mux + the crossbar in Stratix IV is 167 ps. We already have a 72 ps
delay on the connection block input mux (modeled by Ian Kuon), so the remaining
delay within the crossbar is 95 ps.
The delays of cluster feedbacks in Stratix IV is 100 ps, when driven by a LUT.
Since all our outputs LUT outputs go to a BLE output, and have a delay of
25 ps to do so, we subtract 25 ps from the 100 ps delay of a feedback
to get the part that should be marked on the crossbar. -->
<complete name="crossbar" input="clb.I fle[9:0].out" output="fle[9:0].in">
<delay_constant max="95e-12" in_port="clb.I" out_port="fle[9:0].in"/>
<delay_constant max="75e-12" in_port="fle[9:0].out" out_port="fle[9:0].in"/>
</complete>
<complete name="clks" input="clb.clk" output="fle[9:0].clk">
</complete>
<!-- This way of specifying direct connection to clb outputs is important because this architecture uses automatic spreading of opins.
By grouping to output pins in this fashion, if a logic block is completely filled by 6-LUTs,
then the outputs those 6-LUTs take get evenly distributed across all four sides of the CLB instead of clumped on two sides (which is what happens with a more
naive specification).
-->
<direct name="clbouts1" input="fle[9:0].out[0:0]" output="clb.O[9:0]"/>
<direct name="clbouts2" input="fle[9:0].out[1:1]" output="clb.O[19:10]"/>
<!-- Carry chain links -->
<direct name="carry_in" input="clb.cin" output="fle[0:0].cin">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.cin" out_port="fle[0:0].cin"/>
<pack_pattern name="chain" in_port="clb.cin" out_port="fle[0:0].cin"/>
</direct>
<direct name="carry_out" input="fle[9:9].cout" output="clb.cout">
<pack_pattern name="chain" in_port="fle[9:9].cout" out_port="clb.cout"/>
</direct>
<direct name="carry_link" input="fle[8:0].cout" output="fle[9:1].cin">
<pack_pattern name="chain" in_port="fle[8:0].cout" out_port="fle[9:1].cin"/>
</direct>
</interconnect>
</pb_type>
<!-- Define general purpose logic block (CLB) ends -->
<!-- Define single-mode dual-port memory begin -->
<pb_type name="memory">
<input name="waddr" num_pins="10"/>
<input name="raddr" num_pins="10"/>
<input name="d_in" num_pins="32"/>
<input name="wen" num_pins="1"/>
<input name="ren" num_pins="1"/>
<output name="d_out" num_pins="32"/>
<clock name="clk" num_pins="1"/>
<!-- Specify the 512x32=16Kbit memory block
Note: the delay numbers are extracted from VPR flagship XML without modification
Should align to the process technology we using to create the 16K dual-port RAM
-->
<mode name="mem_512x32_dp">
<pb_type name="mem_512x32_dp" blif_model=".subckt dual_port_ram" class="memory" num_pb="1">
<input name="waddr" num_pins="10" port_class="address"/>
<input name="raddr" num_pins="10" port_class="address"/>
<input name="d_in" num_pins="32" port_class="data_in"/>
<input name="wen" num_pins="1" port_class="write_en"/>
<input name="ren" num_pins="1" port_class="write_en"/>
<output name="d_out" num_pins="32" port_class="data_out"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="509e-12" port="mem_512x32_dp.waddr" clock="clk"/>
<T_setup value="509e-12" port="mem_512x32_dp.raddr" clock="clk"/>
<T_setup value="509e-12" port="mem_512x32_dp.d_in" clock="clk"/>
<T_setup value="509e-12" port="mem_512x32_dp.wen" clock="clk"/>
<T_setup value="509e-12" port="mem_512x32_dp.ren" clock="clk"/>
<T_clock_to_Q max="1.234e-9" port="mem_512x32_dp.d_out" clock="clk"/>
<power method="pin-toggle">
<port name="clk" energy_per_toggle="17.9e-12"/>
<static_power power_per_instance="0.0"/>
</power>
</pb_type>
<interconnect>
<direct name="waddress" input="memory.waddr" output="mem_512x32_dp.waddr">
<delay_constant max="132e-12" in_port="memory.waddr" out_port="mem_512x32_dp.waddr"/>
</direct>
<direct name="raddress" input="memory.raddr" output="mem_512x32_dp.raddr">
<delay_constant max="132e-12" in_port="memory.raddr" out_port="mem_512x32_dp.raddr"/>
</direct>
<direct name="data_input" input="memory.d_in" output="mem_512x32_dp.d_in">
<delay_constant max="132e-12" in_port="memory.d_in" out_port="mem_512x32_dp.d_in"/>
</direct>
<direct name="writeen" input="memory.wen" output="mem_512x32_dp.wen">
<delay_constant max="132e-12" in_port="memory.wen" out_port="mem_512x32_dp.wen"/>
</direct>
<direct name="readen" input="memory.ren" output="mem_512x32_dp.ren">
<delay_constant max="132e-12" in_port="memory.ren" out_port="mem_512x32_dp.ren"/>
</direct>
<direct name="dataout" input="mem_512x32_dp.d_out" output="memory.d_out">
<delay_constant max="40e-12" in_port="mem_512x32_dp.d_out" out_port="memory.d_out"/>
</direct>
<direct name="clk" input="memory.clk" output="mem_512x32_dp.clk">
</direct>
</interconnect>
</mode>
</pb_type>
<!-- Define single-mode dual-port memory end -->
</complexblocklist>
</architecture>

View File

@ -292,7 +292,7 @@ bool try_route(int width_fac,
segment_inf, segment_inf,
router_opts.base_cost_type, router_opts.base_cost_type,
router_opts.trim_empty_channels, router_opts.trim_empty_channels,
router_opts.trim_obs_channels, router_opts.trim_obs_channels || det_routing_arch->through_channel,
router_opts.clock_modeling, router_opts.clock_modeling,
directs, num_directs, directs, num_directs,
&warning_count); &warning_count);

View File

@ -172,7 +172,21 @@ size_t get_grid_num_classes(const t_grid_tile& cur_grid,
* When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block * When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block
***********************************************************************/ ***********************************************************************/
bool is_chanx_exist(const DeviceGrid& grids, bool is_chanx_exist(const DeviceGrid& grids,
const vtr::Point<size_t>& chanx_coord) { const vtr::Point<size_t>& chanx_coord,
const bool& through_channel) {
if ((1 > chanx_coord.x()) || (chanx_coord.x() > grids.width() - 2)) {
return false;
}
if (chanx_coord.y() > grids.height() - 2) {
return false;
}
if (true == through_channel) {
return true;
}
return (grids[chanx_coord.x()][chanx_coord.y()].height_offset == grids[chanx_coord.x()][chanx_coord.y()].type->height - 1); return (grids[chanx_coord.x()][chanx_coord.y()].height_offset == grids[chanx_coord.x()][chanx_coord.y()].type->height - 1);
} }
@ -192,9 +206,26 @@ bool is_chanx_exist(const DeviceGrid& grids,
* If the CHANY is in the middle of a multi-width and multi-height grid * If the CHANY is in the middle of a multi-width and multi-height grid
* it should locate at a grid whose width_offset is lower than the its width defined in physical_tile * it should locate at a grid whose width_offset is lower than the its width defined in physical_tile
* When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block * When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block
*
* If through channel is allowed, the chany will always exists
* unless it falls out of the grid array
***********************************************************************/ ***********************************************************************/
bool is_chany_exist(const DeviceGrid& grids, bool is_chany_exist(const DeviceGrid& grids,
const vtr::Point<size_t>& chany_coord) { const vtr::Point<size_t>& chany_coord,
const bool& through_channel) {
if (chany_coord.x() > grids.width() - 2) {
return false;
}
if ((1 > chany_coord.y()) || (chany_coord.y() > grids.height() - 2)) {
return false;
}
if (true == through_channel) {
return true;
}
return (grids[chany_coord.x()][chany_coord.y()].width_offset == grids[chany_coord.x()][chany_coord.y()].type->width - 1); return (grids[chany_coord.x()][chany_coord.y()].width_offset == grids[chany_coord.x()][chany_coord.y()].type->width - 1);
} }

View File

@ -40,10 +40,12 @@ size_t get_grid_num_classes(const t_grid_tile& cur_grid,
const e_pin_type& pin_type); const e_pin_type& pin_type);
bool is_chanx_exist(const DeviceGrid& grids, bool is_chanx_exist(const DeviceGrid& grids,
const vtr::Point<size_t>& chanx_coord); const vtr::Point<size_t>& chanx_coord,
const bool& through_channel=false);
bool is_chany_exist(const DeviceGrid& grids, bool is_chany_exist(const DeviceGrid& grids,
const vtr::Point<size_t>& chany_coord); const vtr::Point<size_t>& chany_coord,
const bool& through_channel=false);
bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids, bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids,
const vtr::Point<size_t>& chanx_coord, const vtr::Point<size_t>& chanx_coord,

View File

@ -186,7 +186,8 @@ size_t estimate_num_chanx_rr_nodes(const DeviceGrid& grids,
vtr::Point<size_t> chanx_coord(ix, iy); vtr::Point<size_t> chanx_coord(ix, iy);
/* Bypass if the routing channel does not exist when through channels are not allowed */ /* Bypass if the routing channel does not exist when through channels are not allowed */
if (false == is_chanx_exist(grids, chanx_coord)) { if ( (false == through_channel)
&& (false == is_chanx_exist(grids, chanx_coord))) {
continue; continue;
} }
@ -237,11 +238,13 @@ size_t estimate_num_chany_rr_nodes(const DeviceGrid& grids,
for (size_t iy = 1; iy < grids.height() - 1; ++iy) { for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
vtr::Point<size_t> chany_coord(ix, iy); vtr::Point<size_t> chany_coord(ix, iy);
/* Bypass if the routing channel does not exist when through channels are not allowed */ /* Bypass if the routing channel does not exist when through channel are not allowed */
if (false == is_chany_exist(grids, chany_coord)) { if ( (false == through_channel)
&& (false == is_chany_exist(grids, chany_coord))) {
continue; continue;
} }
bool force_start = false; bool force_start = false;
bool force_end = false; bool force_end = false;
@ -837,7 +840,7 @@ void load_chanx_rr_nodes_basic_info(RRGraph& rr_graph,
* track0 ----->+-----------------------------+----> track0 * track0 ----->+-----------------------------+----> track0
* | | * | |
*/ */
if (true == is_chanx_exist(grids, chanx_coord)) { if (true == is_chanx_exist(grids, chanx_coord, through_channel)) {
/* Rotate the chanx_details by an offset of ix - 1, the distance to the most left channel */ /* Rotate the chanx_details by an offset of ix - 1, the distance to the most left channel */
/* For INC_DIRECTION, we use clockwise rotation /* For INC_DIRECTION, we use clockwise rotation
* node_id A ----> -----> node_id D * node_id A ----> -----> node_id D
@ -922,7 +925,9 @@ void load_chany_rr_nodes_basic_info(RRGraph& rr_graph,
ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width, grids.height() - 2, ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width, grids.height() - 2,
force_start, force_end, segment_infs); force_start, force_end, segment_infs);
/* Force node_ids from the previous chanx */ /* Force node_ids from the previous chany
* This will not be applied when the routing channel is cut off (force to start)
*/
if (0 < track_node_ids.size()) { if (0 < track_node_ids.size()) {
/* Rotate should be done based on a typical case of routing tracks. /* Rotate should be done based on a typical case of routing tracks.
* Tracks on the borders are not regularly started and ended, * Tracks on the borders are not regularly started and ended,
@ -946,7 +951,7 @@ void load_chany_rr_nodes_basic_info(RRGraph& rr_graph,
* | | * | |
* we should rotate only once at the bottom side of a grid * we should rotate only once at the bottom side of a grid
*/ */
if (true == is_chany_exist(grids, chany_coord)) { if (true == is_chany_exist(grids, chany_coord, through_channel)) {
/* Rotate the chany_details by an offset of 1*/ /* Rotate the chany_details by an offset of 1*/
/* For INC_DIRECTION, we use clockwise rotation /* For INC_DIRECTION, we use clockwise rotation
* node_id A ----> -----> node_id D * node_id A ----> -----> node_id D