Merge pull request #298 from lnis-uofu/micro_benchmarks

Micro benchmarks addition and testing for FPGAs with DSP blocks
This commit is contained in:
tangxifan 2021-04-24 17:55:38 -06:00 committed by GitHub
commit 1baee10e61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1752 additions and 27 deletions

View File

@ -223,7 +223,9 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
.. note:: A ``<pb_type name="<string>">`` parent XML node is required for the interconnect-to-circuit bindings whose interconnects are defined under the ``pb_type`` in VPR architecture description. .. note:: A ``<pb_type name="<string>">`` parent XML node is required for the interconnect-to-circuit bindings whose interconnects are defined under the ``pb_type`` in VPR architecture description.
.. option:: <port name="<string>" physical_mode_port="<string>" .. option:: <port name="<string>" physical_mode_port="<string>"
physical_mode_pin_initial_offset="<int>" physical_mode_pin_rotate_offset="<int>"/> physical_mode_pin_initial_offset="<int>"
physical_mode_pin_rotate_offset="<int>"/>
physical_mode_port_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``
@ -233,7 +235,6 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
.. 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"``) .. 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. - ``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 .. note:: A quick example to understand the initial offset
@ -249,7 +250,24 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
.. note:: If not defined, the default value of ``physical_mode_pin_initial_offset`` is set to ``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, **each time a pin in the operating mode is binded to a pin in the physical mode**.
.. 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]`` with a full path ``mult[frac].mult_9x9[0]``
- operating pb_type ``mult_9x9[1].a[1]`` with a full path ``mult[frac].mult_9x9[1]``
to
- physical pb_type ``mult_36x36.a[0]`` with a full path ``mult[physical].mult_36x36[0]``
- physical pb_type ``mult_36x36.a[9]`` 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``.
.. warning:: The result of using ``physical_mode_pin_rotate_offset`` is fundementally different than ``physical_mode_port_rotate_offset``!!! Please read the examples carefully and pick the one fitting your needs.
- ``physical_mode_port_rotate_offset="<int>"`` aims to align the port 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_port_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, **only when all the pins of a port in the operating mode is binded to all the pins of a port in the physical mode**.
.. note:: A quick example to understand the rotate offset .. note:: A quick example to understand the rotate offset
For example, a rotating offset of 9 is used to map For example, a rotating offset of 9 is used to map
@ -262,7 +280,8 @@ The ``circuit_model_name`` should match the given name of a ``circuit_model`` de
- physical pb_type ``mult_36x36.a[0:8]`` with a full path ``mult[physical].mult_36x36[0]`` - 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]`` - 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:: If not defined, the default value of ``physical_mode_port_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

@ -86,11 +86,11 @@ std::vector<std::string> PbTypeAnnotation::port_names() const {
return keys; return keys;
} }
std::map<BasicPort, std::array<int, 2>> PbTypeAnnotation::physical_pb_type_port(const std::string& port_name) const { std::map<BasicPort, std::array<int, 3>> PbTypeAnnotation::physical_pb_type_port(const std::string& port_name) const {
std::map<std::string, std::map<BasicPort, std::array<int, 2>>>::const_iterator it = operating_pb_type_ports_.find(port_name); std::map<std::string, std::map<BasicPort, std::array<int, 3>>>::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 std::map<BasicPort, std::array<int, 2>>(); return std::map<BasicPort, std::array<int, 3>>();
} }
return operating_pb_type_ports_.at(port_name); return operating_pb_type_ports_.at(port_name);
} }
@ -169,25 +169,25 @@ 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, std::map<BasicPort, std::array<int, 2>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name); std::map<std::string, std::map<BasicPort, std::array<int, 3>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
/* If not exist, initialize and set a default value */ /* If not exist, initialize and set a default value */
if (it == operating_pb_type_ports_.end()) { if (it == operating_pb_type_ports_.end()) {
operating_pb_type_ports_[operating_pb_port_name][physical_pb_port] = {0, 0}; operating_pb_type_ports_[operating_pb_port_name][physical_pb_port] = {0, 0, 0};
/* We can return early */ /* We can return early */
return; return;
} }
/* If the physical port is not in the list, we create one and set a default value */ /* 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)) { 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}; operating_pb_type_ports_[operating_pb_port_name][physical_pb_port] = {0, 0, 0};
} }
} }
void PbTypeAnnotation::set_physical_pin_initial_offset(const std::string& operating_pb_port_name, void PbTypeAnnotation::set_physical_pin_initial_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port, const BasicPort& physical_pb_port,
const int& physical_pin_initial_offset) { 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); std::map<std::string, std::map<BasicPort, std::array<int, 3>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
if (it == operating_pb_type_ports_.end()) { if (it == operating_pb_type_ports_.end()) {
VTR_LOG_ERROR("The operating pb_type port '%s' is not valid!\n", VTR_LOG_ERROR("The operating pb_type port '%s' is not valid!\n",
@ -210,7 +210,7 @@ void PbTypeAnnotation::set_physical_pin_initial_offset(const std::string& operat
void PbTypeAnnotation::set_physical_pin_rotate_offset(const std::string& operating_pb_port_name, void PbTypeAnnotation::set_physical_pin_rotate_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port, const BasicPort& physical_pb_port,
const int& physical_pin_rotate_offset) { 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); std::map<std::string, std::map<BasicPort, std::array<int, 3>>>::const_iterator it = operating_pb_type_ports_.find(operating_pb_port_name);
if (it == operating_pb_type_ports_.end()) { if (it == operating_pb_type_ports_.end()) {
VTR_LOG_ERROR("The operating pb_type port '%s' is not valid!\n", VTR_LOG_ERROR("The operating pb_type port '%s' is not valid!\n",
@ -230,6 +230,30 @@ void PbTypeAnnotation::set_physical_pin_rotate_offset(const std::string& operati
operating_pb_type_ports_[operating_pb_port_name][physical_pb_port][1] = physical_pin_rotate_offset; operating_pb_type_ports_[operating_pb_port_name][physical_pb_port][1] = physical_pin_rotate_offset;
} }
void PbTypeAnnotation::set_physical_port_rotate_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port,
const int& physical_port_rotate_offset) {
std::map<std::string, std::map<BasicPort, std::array<int, 3>>>::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][2] = physical_port_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,
const std::string& circuit_model_name) { const std::string& circuit_model_name) {
std::map<std::string, std::string>::const_iterator it = interconnect_circuit_model_names_.find(interc_name); std::map<std::string, std::string>::const_iterator it = interconnect_circuit_model_names_.find(interc_name);

View File

@ -49,7 +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;
std::map<BasicPort, std::array<int, 2>> physical_pb_type_port(const std::string& port_name) const; std::map<BasicPort, std::array<int, 3>> physical_pb_type_port(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 */
@ -73,6 +73,9 @@ class PbTypeAnnotation {
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 BasicPort& physical_pb_port,
const int& physical_pin_rotate_offset); const int& physical_pin_rotate_offset);
void set_physical_port_rotate_offset(const std::string& operating_pb_port_name,
const BasicPort& physical_pb_port,
const int& physical_port_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);
private: /* Internal data */ private: /* Internal data */
@ -138,10 +141,10 @@ class PbTypeAnnotation {
int physical_pb_type_index_offset_; int physical_pb_type_index_offset_;
/* Link from the pins under an operating pb_type to pairs of /* Link from the pins under an operating pb_type to pairs of
* its physical pb_type and its pin initial & rotating offset * its physical pb_type and
* * - its pin initial offset: the first element of the std::array
* Note that initial offset is the first element of the std::array * - pin-level rotating offset: the second element of the std::array
* Note that rotating offset is the second element of the std::array * - port-level rotating offset: the third element of the std::array
* *
* The offsets aim to align the pin indices for port of pb_type * 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
@ -158,14 +161,21 @@ class PbTypeAnnotation {
* physical pb_type bram[0].dout_a[0] with a full path memory[physical].bram[0] * 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] * 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 * For example, a pin-level rotating offset of 9 is used to map
* operating pb_type mult_9x9[0].a[0] with a full path mult[frac].mult_9x9[0]
* operating pb_type mult_9x9[0].a[1] with a full path mult[frac].mult_9x9[1]
* to
* physical pb_type mult_36x36.a[0] with a full path mult[physical].mult_36x36[0]
* physical pb_type mult_36x36.a[9] with a full path mult[physical].mult_36x36[0]
*
* For example, a port-level 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[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] * operating pb_type mult_9x9[1].a[0:8] with a full path mult[frac].mult_9x9[1]
* to * to
* physical pb_type mult_36x36.a[0:8] with a full path mult[physical].mult_36x36[0] * 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] * physical pb_type mult_36x36.a[9:17] with a full path mult[physical].mult_36x36[0]
*/ */
std::map<std::string, std::map<BasicPort, std::array<int, 2>>> operating_pb_type_ports_; std::map<std::string, std::map<BasicPort, std::array<int, 3>>> 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

@ -114,6 +114,31 @@ void read_xml_pb_port_annotation(pugi::xml_node& xml_port,
std::stoi(rotate_offsets[iport])); std::stoi(rotate_offsets[iport]));
} }
} }
/* We have an optional attribute: physical_mode_port_rotate_offset
* Split based on the number of physical pb_type ports that have been defined
*/
const std::string& physical_port_rotate_offset_attr = get_attribute(xml_port, "physical_mode_port_rotate_offset", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string();
if (false == physical_port_rotate_offset_attr.empty()) {
/* Split the physical mode port attributes with space */
openfpga::StringToken offset_tokenizer(physical_port_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 port 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_port_rotate_offset(name_attr,
port_parser.port(),
std::stoi(rotate_offsets[iport]));
}
}
} }
/******************************************************************** /********************************************************************

View File

@ -144,7 +144,14 @@ void write_xml_pb_port_annotation(std::fstream& fp,
physical_mode_pin_rotate_offset_attr += std::to_string(physical_pb_port_pair.second[1]); 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()); write_xml_attribute(fp, "physical_mode_pin_rotate_offset", physical_mode_pin_rotate_offset_attr.c_str());
std::string physical_mode_port_rotate_offset_attr;
for (const auto& physical_pb_port_pair : pb_type_annotation.physical_pb_type_port(port_name)) {
if (false == physical_mode_port_rotate_offset_attr.empty()) {
physical_mode_port_rotate_offset_attr += " ";
}
physical_mode_port_rotate_offset_attr += std::to_string(physical_pb_port_pair.second[2]);
}
write_xml_attribute(fp, "physical_mode_port_rotate_offset", physical_mode_port_rotate_offset_attr.c_str());
fp << "/>" << "\n"; fp << "/>" << "\n";
} }

View File

@ -333,7 +333,7 @@ bool try_match_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin,
* 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 acc_offset = vpr_device_annotation.physical_pb_pin_offset(operating_pb_graph_pin->port, candidate_port); int acc_offset = vpr_device_annotation.physical_pb_pin_offset(operating_pb_graph_pin->port, candidate_port) + vpr_device_annotation.physical_pb_port_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); 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); 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 if (physical_pb_graph_pin->pin_number != operating_pb_graph_pin->pin_number
@ -463,6 +463,14 @@ void annotate_physical_pb_graph_node_pins(t_pb_graph_node* operating_pb_graph_no
physical_pb_graph_node, vpr_device_annotation, physical_pb_graph_node, vpr_device_annotation,
verbose_output); verbose_output);
} }
/* Finish a port, accumulate the port-level offset affiliated to the port */
if (0 == operating_pb_graph_node->num_input_pins[iport]) {
continue;
}
t_pb_graph_pin* operating_pb_graph_pin = &(operating_pb_graph_node->input_pins[iport][0]);
for (t_port* candidate_port : vpr_device_annotation.physical_pb_port(operating_pb_graph_pin->port)) {
vpr_device_annotation.accumulate_physical_pb_port_rotate_offset(operating_pb_graph_pin->port, candidate_port);
}
} }
for (int iport = 0; iport < operating_pb_graph_node->num_output_ports; ++iport) { for (int iport = 0; iport < operating_pb_graph_node->num_output_ports; ++iport) {
@ -471,6 +479,14 @@ void annotate_physical_pb_graph_node_pins(t_pb_graph_node* operating_pb_graph_no
physical_pb_graph_node, vpr_device_annotation, physical_pb_graph_node, vpr_device_annotation,
verbose_output); verbose_output);
} }
/* Finish a port, accumulate the port-level offset affiliated to the port */
if (0 == operating_pb_graph_node->num_output_pins[iport]) {
continue;
}
t_pb_graph_pin* operating_pb_graph_pin = &(operating_pb_graph_node->output_pins[iport][0]);
for (t_port* candidate_port : vpr_device_annotation.physical_pb_port(operating_pb_graph_pin->port)) {
vpr_device_annotation.accumulate_physical_pb_port_rotate_offset(operating_pb_graph_pin->port, candidate_port);
}
} }
for (int iport = 0; iport < operating_pb_graph_node->num_clock_ports; ++iport) { for (int iport = 0; iport < operating_pb_graph_node->num_clock_ports; ++iport) {
@ -479,6 +495,14 @@ void annotate_physical_pb_graph_node_pins(t_pb_graph_node* operating_pb_graph_no
physical_pb_graph_node, vpr_device_annotation, physical_pb_graph_node, vpr_device_annotation,
verbose_output); verbose_output);
} }
/* Finish a port, accumulate the port-level offset affiliated to the port */
if (0 == operating_pb_graph_node->num_clock_pins[iport]) {
continue;
}
t_pb_graph_pin* operating_pb_graph_pin = &(operating_pb_graph_node->clock_pins[iport][0]);
for (t_port* candidate_port : vpr_device_annotation.physical_pb_port(operating_pb_graph_pin->port)) {
vpr_device_annotation.accumulate_physical_pb_port_rotate_offset(operating_pb_graph_pin->port, candidate_port);
}
} }
} }

View File

@ -211,7 +211,7 @@ 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)) {
std::map<BasicPort, std::array<int, 2>> expected_physical_pb_ports = pb_type_annotation.physical_pb_type_port(std::string(operating_pb_port->name)); std::map<BasicPort, std::array<int, 3>> expected_physical_pb_ports = pb_type_annotation.physical_pb_type_port(std::string(operating_pb_port->name));
/* If not defined in the annotation, set the default pair: /* If not defined in the annotation, set the default pair:
* rotate_offset is 0 by default! * rotate_offset is 0 by default!
@ -243,6 +243,7 @@ bool pair_operating_and_physical_pb_types(t_pb_type* operating_pb_type,
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_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_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]); vpr_device_annotation.add_physical_pb_pin_rotate_offset(operating_pb_port, physical_pb_port, expected_physical_pb_port.second[1]);
vpr_device_annotation.add_physical_pb_port_rotate_offset(operating_pb_port, physical_pb_port, expected_physical_pb_port.second[2]);
} }
} }

View File

@ -220,6 +220,21 @@ int VprDeviceAnnotation::physical_pb_pin_rotate_offset(t_port* operating_pb_port
return physical_pb_pin_rotate_offsets_.at(operating_pb_port).at(physical_pb_port); return physical_pb_pin_rotate_offsets_.at(operating_pb_port).at(physical_pb_port);
} }
int VprDeviceAnnotation::physical_pb_port_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_port_rotate_offsets_.find(operating_pb_port);
if (it == physical_pb_port_rotate_offsets_.end()) {
/* Default value is 0 */
return 0;
}
if (0 == physical_pb_port_rotate_offsets_.at(operating_pb_port).count(physical_pb_port)) {
/* Default value is 0 */
return 0;
}
return physical_pb_port_rotate_offsets_.at(operating_pb_port).at(physical_pb_port);
}
int VprDeviceAnnotation::physical_pb_pin_offset(t_port* operating_pb_port, int VprDeviceAnnotation::physical_pb_pin_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const { t_port* physical_pb_port) const {
/* Ensure that the pb_type is in the list */ /* Ensure that the pb_type is in the list */
@ -235,6 +250,21 @@ int VprDeviceAnnotation::physical_pb_pin_offset(t_port* operating_pb_port,
return physical_pb_pin_offsets_.at(operating_pb_port).at(physical_pb_port); return physical_pb_pin_offsets_.at(operating_pb_port).at(physical_pb_port);
} }
int VprDeviceAnnotation::physical_pb_port_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_port_offsets_.find(operating_pb_port);
if (it == physical_pb_port_offsets_.end()) {
/* Default value is 0 */
return 0;
}
if (0 == physical_pb_port_offsets_.at(operating_pb_port).count(physical_pb_port)) {
/* Default value is 0 */
return 0;
}
return physical_pb_port_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);
@ -478,6 +508,28 @@ void VprDeviceAnnotation::add_physical_pb_pin_initial_offset(t_port* operating_p
physical_pb_pin_initial_offsets_[operating_pb_port][physical_pb_port] = offset; physical_pb_pin_initial_offsets_[operating_pb_port][physical_pb_port] = offset;
} }
void VprDeviceAnnotation::add_physical_pb_port_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_port_rotate_offsets_.find(operating_pb_port);
if ( (it != physical_pb_port_rotate_offsets_.end())
&& (0 < physical_pb_port_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' port rotate offset '%d'!\n",
operating_pb_port->name, offset);
}
physical_pb_port_rotate_offsets_[operating_pb_port][physical_pb_port] = offset;
/* We initialize the accumulated offset to 0 */
physical_pb_port_offsets_[operating_pb_port][physical_pb_port] = 0;
}
void VprDeviceAnnotation::accumulate_physical_pb_port_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port) {
physical_pb_port_offsets_[operating_pb_port][physical_pb_port] += physical_pb_port_rotate_offsets_[operating_pb_port][physical_pb_port];
}
void VprDeviceAnnotation::add_physical_pb_pin_rotate_offset(t_port* operating_pb_port, void VprDeviceAnnotation::add_physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port, t_port* physical_pb_port,
const int& offset) { const int& offset) {

View File

@ -67,6 +67,9 @@ class VprDeviceAnnotation {
int physical_pb_pin_rotate_offset(t_port* operating_pb_port, int physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const; t_port* physical_pb_port) const;
int physical_pb_port_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
* It is an aggregation of the offset during pin pairing * It is an aggregation of the offset during pin pairing
@ -76,6 +79,8 @@ class VprDeviceAnnotation {
*/ */
int physical_pb_pin_offset(t_port* operating_pb_port, int physical_pb_pin_offset(t_port* operating_pb_port,
t_port* physical_pb_port) const; t_port* physical_pb_port) const;
int physical_pb_port_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;
@ -106,6 +111,11 @@ class VprDeviceAnnotation {
void add_physical_pb_pin_initial_offset(t_port* operating_pb_port, void add_physical_pb_pin_initial_offset(t_port* operating_pb_port,
t_port* physical_pb_port, t_port* physical_pb_port,
const int& offset); const int& offset);
void add_physical_pb_port_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port,
const int& offset);
void accumulate_physical_pb_port_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port);
void add_physical_pb_pin_rotate_offset(t_port* operating_pb_port, void add_physical_pb_pin_rotate_offset(t_port* operating_pb_port,
t_port* physical_pb_port, t_port* physical_pb_port,
const int& offset); const int& offset);
@ -166,8 +176,11 @@ class VprDeviceAnnotation {
std::map<t_port*, std::vector<t_port*>> physical_pb_ports_; std::map<t_port*, std::vector<t_port*>> physical_pb_ports_;
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_initial_offsets_;
std::map<t_port*, std::map<t_port*, int>> physical_pb_pin_rotate_offsets_; std::map<t_port*, std::map<t_port*, int>> physical_pb_pin_rotate_offsets_;
std::map<t_port*, std::map<t_port*, int>> physical_pb_port_rotate_offsets_;
/* Accumulated offsets for a physical pb_type port, just for internal usage */ /* Accumulated offsets for a physical pb port, just for internal usage */
std::map<t_port*, std::map<t_port*, int>> physical_pb_port_offsets_;
/* Accumulated offsets for a physical pb_graph_pin, just for internal usage */
std::map<t_port*, 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

View File

@ -28,6 +28,8 @@ namespace openfpga {
* - sink is an input of a primitive pb_type * - sink is an input of a primitive pb_type
* *
* Note: * Note:
* - This function is applicable ONLY to single-mode pb_types!!! Because their routing traces
* are deterministic: there is only 1 valid path from a source pin to a sink pin!!!
* - If there is a fan-out of the current source pb graph pin is not a direct interconnection * - If there is a fan-out of the current source pb graph pin is not a direct interconnection
* the direct search should stop. * the direct search should stop.
* - This function is designed for pb graph without local routing * - This function is designed for pb graph without local routing
@ -58,6 +60,11 @@ bool rec_direct_search_sink_pb_graph_pins(const t_pb_graph_pin* source_pb_pin,
std::vector<t_pb_graph_pin*> sink_pb_pins_to_search; std::vector<t_pb_graph_pin*> sink_pb_pins_to_search;
/* Only support single-mode pb_type!!! */
//if (1 != source_pb_pin->parent_node->pb_type->num_modes) {
// return false;
//}
for (int iedge = 0; iedge < source_pb_pin->num_output_edges; ++iedge) { for (int iedge = 0; iedge < source_pb_pin->num_output_edges; ++iedge) {
if (DIRECT_INTERC != source_pb_pin->output_edges[iedge]->interconnect->type) { if (DIRECT_INTERC != source_pb_pin->output_edges[iedge]->interconnect->type) {
return false; return false;

View File

@ -0,0 +1,22 @@
//-------------------------------------------------------
// Functionality: A 12-bit multiply-acculumate circuit
// Author: Xifan Tang
//-------------------------------------------------------
module mac_12(a, b, c, out);
parameter DATA_WIDTH = 12; /* declare a parameter. default required */
input [DATA_WIDTH - 1 : 0] a, b, c;
output [DATA_WIDTH - 1 : 0] out;
assign out = a * b + c;
endmodule

View File

@ -0,0 +1,22 @@
//-------------------------------------------------------
// Functionality: A 16-bit multiply-acculumate circuit
// Author: Xifan Tang
//-------------------------------------------------------
module mac_16(a, b, c, out);
parameter DATA_WIDTH = 16; /* declare a parameter. default required */
input [DATA_WIDTH - 1 : 0] a, b, c;
output [DATA_WIDTH - 1 : 0] out;
assign out = a * b + c;
endmodule

View File

@ -0,0 +1,22 @@
//-------------------------------------------------------
// Functionality: A 2-bit multiply-acculumate circuit
// Author: Xifan Tang
//-------------------------------------------------------
module mac_2(a, b, c, out);
parameter DATA_WIDTH = 2; /* declare a parameter. default required */
input [DATA_WIDTH - 1 : 0] a, b, c;
output [DATA_WIDTH - 1 : 0] out;
assign out = a * b + c;
endmodule

View File

@ -0,0 +1,22 @@
//-------------------------------------------------------
// Functionality: A 32-bit multiply-acculumate circuit
// Author: Xifan Tang
//-------------------------------------------------------
module mac_32(a, b, c, out);
parameter DATA_WIDTH = 32; /* declare a parameter. default required */
input [DATA_WIDTH - 1 : 0] a, b, c;
output [DATA_WIDTH - 1 : 0] out;
assign out = a * b + c;
endmodule

View File

@ -0,0 +1,22 @@
//-------------------------------------------------------
// Functionality: A 4-bit multiply-acculumate circuit
// Author: Xifan Tang
//-------------------------------------------------------
module mac_4(a, b, c, out);
parameter DATA_WIDTH = 4; /* declare a parameter. default required */
input [DATA_WIDTH - 1 : 0] a, b, c;
output [DATA_WIDTH - 1 : 0] out;
assign out = a * b + c;
endmodule

View File

@ -0,0 +1,22 @@
//-------------------------------------------------------
// Functionality: A 6-bit multiply-acculumate circuit
// Author: Xifan Tang
//-------------------------------------------------------
module mac_6(a, b, c, out);
parameter DATA_WIDTH = 6; /* declare a parameter. default required */
input [DATA_WIDTH - 1 : 0] a, b, c;
output [DATA_WIDTH - 1 : 0] out;
assign out = a * b + c;
endmodule

View File

@ -262,7 +262,6 @@
<!-- Binding operating pb_type to physical pb_type --> <!-- Binding operating pb_type to physical pb_type -->
<!-- Binding operating pb_types in mode 'arithmetic' --> <!-- Binding operating pb_types in mode 'arithmetic' -->
<pb_type name="clb.fle[arithmetic].soft_adder.adder_lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1"/> <pb_type name="clb.fle[arithmetic].soft_adder.adder_lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1"/>
<pb_type name="clb.fle[arithmetic].soft_adder.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<pb_type name="clb.fle[arithmetic].soft_adder.carry_follower" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.carry_follower"/> <pb_type name="clb.fle[arithmetic].soft_adder.carry_follower" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.carry_follower"/>
<!-- Binding operating pb_types in mode 'n2_lut3' --> <!-- Binding operating pb_types in mode 'n2_lut3' -->
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.lut3" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1" physical_pb_type_index_factor="0.5"> <pb_type name="clb.fle[n2_lut3].lut3inter.ble3.lut3" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1" physical_pb_type_index_factor="0.5">

View File

@ -0,0 +1,295 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k4_frac_cc_sky130nm.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
- Skywater 130nm PDK
- circuit models are binded to the opensource skywater
foundry middle-speed (ms) standard cell library
-->
<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="sky130_fd_sc_hd__inv_1" prefix="sky130_fd_sc_hd__inv_1" is_default="true">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="Y" 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="sky130_fd_sc_hd__buf_2" prefix="sky130_fd_sc_hd__buf_2" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="2"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="X" 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="sky130_fd_sc_hd__buf_4" prefix="sky130_fd_sc_hd__buf_4" 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" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="X" 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="sky130_fd_sc_hd__inv_2" prefix="sky130_fd_sc_hd__inv_2" is_default="false">
<design_technology type="cmos" topology="buffer" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="Y" 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="sky130_fd_sc_hd__or2_1" prefix="sky130_fd_sc_hd__or2_1" 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" lib_name="A" size="1"/>
<port type="input" prefix="b" lib_name="B" size="1"/>
<port type="output" prefix="out" lib_name="X" 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>
<!-- Define a circuit model for the standard cell MUX2
OpenFPGA requires the following truth table for the MUX2
When the select signal sel is enabled, the first input, i.e., in0
will be propagated to the output, i.e., out
If your standard cell provider does not offer the exact truth table,
you can simply swap the inputs as shown in the example below
-->
<circuit_model type="gate" name="sky130_fd_sc_hd__mux2_1" prefix="sky130_fd_sc_hd__mux2_1">
<design_technology type="cmos" topology="MUX2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in0" lib_name="A1" size="1"/>
<port type="input" prefix="in1" lib_name="A0" size="1"/>
<port type="input" prefix="sel" lib_name="S" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
</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_tree" prefix="mux_tree" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<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_tree_tapbuf" prefix="mux_tree_tapbuf" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_4"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<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="SDFFRQ" prefix="SDFFRQ" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="DI" lib_name="SI" size="1"/>
<port type="input" prefix="Test_en" lib_name="SE" size="1" is_global="true" default_val="0"/>
<port type="input" prefix="reset" lib_name="RST" size="1" default_val="0"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" lib_name="CK" size="1" default_val="0" />
</circuit_model>
<circuit_model type="lut" name="frac_lut4" prefix="frac_lut4" dump_structural_verilog="true">
<design_technology type="cmos" fracturable_lut="true"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_input_inverter exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<lut_input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_intermediate_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2" location_map="-1-"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="4" tri_state_map="---1" circuit_model_name="sky130_fd_sc_hd__or2_1"/>
<port type="output" prefix="lut2_out" size="2" lut_frac_level="2" lut_output_mask="2,3"/>
<port type="output" prefix="lut3_out" size="2" lut_frac_level="3" lut_output_mask="0,1"/>
<port type="output" prefix="lut4_out" size="1" lut_output_mask="0"/>
<port type="sram" prefix="sram" size="16"/>
<port type="sram" prefix="mode" size="1" mode_select="true" circuit_model_name="DFFRQ" 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="DFFRQ" prefix="DFFRQ" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="RST" size="1" is_global="true" default_val="0" is_prog="true" is_reset="true"/>
</circuit_model>
<circuit_model type="iopad" name="EMBEDDED_IO_ISOLN" prefix="EMBEDDED_IO_ISOLN" is_default="true" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/gpio.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="SOC_IN" lib_name="SOC_IN" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="output" prefix="SOC_OUT" lib_name="SOC_OUT" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="output" prefix="SOC_DIR" lib_name="SOC_DIR" size="1" is_global="true" is_io="true"/>
<port type="input" prefix="IO_ISOL_N" lib_name="IO_ISOL_N" size="1" is_global="true" default_val="1"/>
<port type="output" prefix="inpad" lib_name="FPGA_IN" size="1"/>
<port type="input" prefix="outpad" lib_name="FPGA_OUT" size="1"/>
<port type="sram" prefix="en" lib_name="FPGA_DIR" size="1" mode_select="true" circuit_model_name="DFFRQ" default_val="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="CARRY_MUX2" prefix="CARRY_MUX2" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/mux2.v">
<design_technology type="cmos"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="a" lib_name="A0" size="1"/>
<port type="input" prefix="b" lib_name="A1" size="1"/>
<port type="input" prefix="cin" lib_name="S" size="1"/>
<port type="output" prefix="cout" lib_name="Y" size="1"/>
</circuit_model>
<circuit_model type="hard_logic" name="frac_mult_16x16" prefix="frac_mult_16x16" is_default="true" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/frac_mult_16x16.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/frac_mult_16x16.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" lib_name="a" size="16"/>
<port type="input" prefix="B" lib_name="b" size="16"/>
<port type="output" prefix="Y" lib_name="out" size="32"/>
<port type="sram" prefix="mode" lib_name="mode" size="1" mode_select="true" circuit_model_name="DFFRQ" default_val="0"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="DFFRQ" num_regions="1"/>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_tree_tapbuf"/>
</connection_block>
<switch_block>
<switch name="L1_mux" circuit_model_name="mux_tree_tapbuf"/>
<switch name="L2_mux" circuit_model_name="mux_tree_tapbuf"/>
<switch name="L4_mux" circuit_model_name="mux_tree_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L1" circuit_model_name="chan_segment"/>
<segment name="L2" circuit_model_name="chan_segment"/>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<direct_connection>
<direct name="carry_chain" circuit_model_name="direct_interc"/>
<direct name="shift_register" circuit_model_name="direct_interc"/>
<direct name="scan_chain" circuit_model_name="direct_interc" type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
<tile_annotations>
<global_port name="clk" is_clock="true" default_val="0">
<tile name="clb" port="clk" x="-1" y="-1"/>
</global_port>
<global_port name="Reset" is_reset="true" default_val="1">
<tile name="clb" port="reset" x="-1" y="-1"/>
</global_port>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<!-- IMPORTANT: must set unused I/Os to operating in INPUT mode !!! -->
<pb_type name="io[physical].iopad" circuit_model_name="EMBEDDED_IO_ISOLN" 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.fle" physical_mode_name="physical"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.frac_lut4" circuit_model_name="frac_lut4" mode_bits="0"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.carry_follower" circuit_model_name="CARRY_MUX2"/>
<pb_type name="clb.fle[physical].fabric.ff" circuit_model_name="SDFFRQ"/>
<!-- Binding operating pb_type to physical pb_type -->
<!-- Binding operating pb_types in mode 'arithmetic' -->
<pb_type name="clb.fle[arithmetic].soft_adder.adder_lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1"/>
<pb_type name="clb.fle[arithmetic].soft_adder.carry_follower" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.carry_follower"/>
<!-- Binding operating pb_types in mode 'n2_lut3' -->
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.lut3" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="1" physical_pb_type_index_factor="0.5">
<!-- Binding the lut3 to the first 3 inputs of fracturable lut4 -->
<port name="in" physical_mode_port="in[0:2]"/>
<port name="out" physical_mode_port="lut3_out[0:0]" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- Binding operating pb_types in mode 'ble4' -->
<pb_type name="clb.fle[n1_lut4].ble4.lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4" mode_bits="0">
<!-- Binding the lut4 to the first 4 inputs of fracturable lut4 -->
<port name="in" physical_mode_port="in[0:3]"/>
<port name="out" physical_mode_port="lut4_out"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.ff" physical_pb_type_name="clb.fle[physical].fabric.ff" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0"/>
<!-- Binding operating pb_types in mode 'shift_register' -->
<pb_type name="clb.fle[shift_register].shift_reg.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block dsp -->
<pb_type name="mult_16" physical_mode_name="mult_16x16"/>
<!-- Bind the primitive pb_type in the physical mode to a circuit model -->
<pb_type name="mult_16[mult_16x16].mult_16x16_slice.mult_16x16" circuit_model_name="frac_mult_16x16" mode_bits="0"/>
<pb_type name="mult_16[mult_8x8].mult_8x8_slice.mult_8x8" physical_pb_type_name="mult_16[mult_16x16].mult_16x16_slice.mult_16x16" mode_bits="1" physical_pb_type_index_factor="0">
<port name="A" physical_mode_port="A[0:7]" physical_mode_port_rotate_offset="8"/>
<port name="B" physical_mode_port="B[0:7]" physical_mode_port_rotate_offset="8"/>
<port name="Y" physical_mode_port="Y[0:15]" physical_mode_port_rotate_offset="16"/>
</pb_type>
</pb_type_annotations>
</openfpga_architecture>

View File

@ -0,0 +1,29 @@
//-----------------------------------------------------
// Design Name : frac_mult_16x16
// File Name : frac_mult_16x16.v
// Function : A 16-bit multiplier which can operate in fracturable modes:
// 1. two 8-bit multipliers
// 2. one 16-bit multipliers
// Coder : Xifan Tang
//-----------------------------------------------------
module frac_mult_16x16 (
input [0:15] a,
input [0:15] b,
output [0:31] out,
input [0:0] mode);
reg [0:31] out_reg;
always @(mode, a, b) begin
if (1'b1 == mode) begin
out_reg[0:15] <= a[0:7] * b[0:7];
out_reg[16:31] <= a[8:15] * b[8:15];
end else begin
out_reg <= a * b;
end
end
assign out = out_reg;
endmodule

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 --device ${OPENFPGA_VPR_DEVICE_LAYOUT} vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --device ${OPENFPGA_VPR_DEVICE_LAYOUT} --constant_net_method route
# 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,25 @@
//-----------------------------
// 8-bit multiplier
//-----------------------------
module mult_8(
input [0:7] A,
input [0:7] B,
output [0:15] Y
);
assign Y = A * B;
endmodule
//-----------------------------
// 16-bit multiplier
//-----------------------------
module mult_16(
input [0:15] A,
input [0:15] B,
output [0:31] Y
);
assign Y = A * B;
endmodule

View File

@ -0,0 +1,41 @@
//-----------------------------
// 8-bit multiplier
//-----------------------------
module mult_8x8 (
input [0:7] A,
input [0:7] B,
output [0:15] Y
);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
mult_8 #() _TECHMAP_REPLACE_ (
.A (A),
.B (B),
.Y (Y) );
endmodule
//-----------------------------
// 16-bit multiplier
//-----------------------------
module mult_16x16 (
input [0:15] A,
input [0:15] B,
output [0:31] Y
);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
mult_16 #() _TECHMAP_REPLACE_ (
.A (A),
.B (B),
.Y (Y) );
endmodule

View File

@ -47,6 +47,9 @@ run-task fpga_verilog/bram/wide_dpram16k --debug --show_thread_logs
echo -e "Testing Verilog generation with heterogeneous fabric using 8-bit single-mode multipliers "; echo -e "Testing Verilog generation with heterogeneous fabric using 8-bit single-mode multipliers ";
run-task fpga_verilog/dsp/single_mode_mult_8x8 --debug --show_thread_logs run-task fpga_verilog/dsp/single_mode_mult_8x8 --debug --show_thread_logs
echo -e "Testing Verilog generation with heterogeneous fabric using 16-bit multi-mode multipliers ";
run-task fpga_verilog/dsp/multi_mode_mult_16x16 --debug --show_thread_logs
echo -e "Testing Verilog generation with different I/O capacities on each side of an FPGA "; echo -e "Testing Verilog generation with different I/O capacities on each side of an FPGA ";
run-task fpga_verilog/io/multi_io_capacity --debug --show_thread_logs run-task fpga_verilog/io/multi_io_capacity --debug --show_thread_logs

View File

@ -0,0 +1,49 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = false
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/fix_heterogeneous_device_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_frac_dsp16_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
# Yosys script parameters
yosys_cell_sim_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k4_frac_N8_tileable_reset_softadder_register_scan_chain_frac_dsp16_nonLR_caravel_io_skywater130nm_cell_sim.v
yosys_dsp_map_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k4_frac_N8_tileable_reset_softadder_register_scan_chain_frac_dsp16_nonLR_caravel_io_skywater130nm_dsp_map.v
yosys_dsp_map_parameters=-D DSP_A_MAXWIDTH=8 -D DSP_B_MAXWIDTH=8 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_8x8
# VPR parameter
openfpga_vpr_device_layout=3x4
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_frac_dsp16_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_4/mac_4.v
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_8/mac_8.v
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_12/mac_12.v
bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_16/mac_16.v
[SYNTHESIS_PARAM]
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dsp_flow.ys
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
bench0_top = mac_4
bench1_top = mac_8
bench2_top = mac_12
bench3_top = mac_16
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -30,13 +30,19 @@ openfpga_vpr_device_layout=3x2
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_dsp8_nonLR_caravel_io_skywater130nm.xml arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_dsp8_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS] [BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac_8/mac_8.v bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_2/mac_2.v
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_4/mac_4.v
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_6/mac_6.v
bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/mac/mac_8/mac_8.v
[SYNTHESIS_PARAM] [SYNTHESIS_PARAM]
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dsp_flow.ys bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dsp_flow.ys
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys
bench0_top = mac_8 bench0_top = mac_2
bench1_top = mac_4
bench2_top = mac_6
bench3_top = mac_8
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] [SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test= end_flow_with_test=

View File

@ -0,0 +1,964 @@
<!--
Low-cost homogeneous FPGA Architecture.
- Skywater 130 nm technology
- General purpose logic block:
K = 4, N = 8, fracturable 4 LUTs (can operate as one 4-LUT or two 3-LUTs with all 3 inputs shared)
with optionally registered outputs
- Heterogeneous block
8-bit multiplier
- Routing architecture:
- 10% L = 1, fc_in = 0.15, Fc_out = 0.10
- 10% L = 2, fc_in = 0.15, Fc_out = 0.10
- 80% L = 4, fc_in = 0.15, Fc_out = 0.10
- 100 routing tracks per channel
Authors: Xifan Tang
-->
<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="mult_8">
<input_ports>
<port name="A" combinational_sink_ports="Y"/>
<port name="B" combinational_sink_ports="Y"/>
</input_ports>
<output_ports>
<port name="Y"/>
</output_ports>
</model>
<model name="mult_16">
<input_ports>
<port name="A" combinational_sink_ports="Y"/>
<port name="B" combinational_sink_ports="Y"/>
</input_ports>
<output_ports>
<port name="Y"/>
</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>
<model name="adder_lut4">
<input_ports>
<port name="in" combinational_sink_ports="lut2_out lut4_out"/>
</input_ports>
<output_ports>
<port name="lut2_out"/>
<port name="lut4_out"/>
</output_ports>
</model>
<model name="carry_follower">
<input_ports>
<port name="a" combinational_sink_ports="cout"/>
<port name="b" combinational_sink_ports="cout"/>
<port name="cin" combinational_sink_ports="cout"/>
</input_ports>
<output_ports>
<port name="cout"/>
</output_ports>
</model>
<model name="frac_lut4">
<input_ports>
<port name="in"/>
</input_ports>
<output_ports>
<port name="lut2_out"/>
<port name="lut3_out"/>
<port name="lut4_out"/>
</output_ports>
</model>
<model name="carry_follower_physical">
<input_ports>
<port name="a" combinational_sink_ports="cout"/>
<port name="b" combinational_sink_ports="cout"/>
<port name="cin" combinational_sink_ports="cout"/>
</input_ports>
<output_ports>
<port name="cout"/>
</output_ports>
</model>
<!-- A virtual model for scan-chain flip-flop to be used in the physical mode of FF -->
<model name="scff">
<input_ports>
<port name="D" clock="clk"/>
<port name="DI" clock="clk"/>
<port name="reset" clock="clk"/>
<port name="clk" is_clock="1"/>
</input_ports>
<output_ports>
<port name="Q" clock="clk"/>
</output_ports>
</model>
</models>
<tiles>
<!-- 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
-->
<!-- Top-side has 1 I/O per tile -->
<tile name="io_top" capacity="9" 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="bottom">io_top.outpad io_top.inpad</loc>
</pinlocations>
</tile>
<!-- Right-side has 1 I/O per tile -->
<tile name="io_right" capacity="9" 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_right.outpad io_right.inpad</loc>
</pinlocations>
</tile>
<!-- Bottom-side has 9 I/O per tile -->
<tile name="io_bottom" capacity="9" 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="top">io_bottom.outpad io_bottom.inpad</loc>
</pinlocations>
</tile>
<!-- Left-side has 1 I/O per tile -->
<tile name="io_left" capacity="9" 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="right">io_left.outpad io_left.inpad</loc>
</pinlocations>
</tile>
<!-- CLB has most pins on the top and right sides -->
<tile name="clb" area="53894">
<equivalent_sites>
<site pb_type="clb"/>
</equivalent_sites>
<input name="I0" num_pins="2" equivalent="full"/>
<input name="I0i" num_pins="2" equivalent="none"/>
<input name="I1" num_pins="2" equivalent="full"/>
<input name="I1i" num_pins="2" equivalent="none"/>
<input name="I2" num_pins="2" equivalent="full"/>
<input name="I2i" num_pins="2" equivalent="none"/>
<input name="I3" num_pins="2" equivalent="full"/>
<input name="I3i" num_pins="2" equivalent="none"/>
<input name="I4" num_pins="2" equivalent="full"/>
<input name="I4i" num_pins="2" equivalent="none"/>
<input name="I5" num_pins="2" equivalent="full"/>
<input name="I5i" num_pins="2" equivalent="none"/>
<input name="I6" num_pins="2" equivalent="full"/>
<input name="I6i" num_pins="2" equivalent="none"/>
<input name="I7" num_pins="2" equivalent="full"/>
<input name="I7i" num_pins="2" equivalent="none"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1" is_non_clock_global="true"/>
<output name="O" num_pins="16" equivalent="none"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<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="reg_in" fc_type="frac" fc_val="0"/>
<fc_override port_name="reg_out" fc_type="frac" fc_val="0"/>
<fc_override port_name="sc_in" fc_type="frac" fc_val="0"/>
<fc_override port_name="sc_out" fc_type="frac" fc_val="0"/>
<fc_override port_name="cin" fc_type="frac" fc_val="0"/>
<fc_override port_name="cout" fc_type="frac" fc_val="0"/>
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
<fc_override port_name="reset" fc_type="frac" fc_val="0"/>
</fc>
<!--pinlocations pattern="spread"/-->
<pinlocations pattern="custom">
<loc side="left">clb.clk clb.reset</loc>
<loc side="top">clb.reg_in clb.sc_in clb.cin clb.O[7:0] clb.I0 clb.I0i clb.I1 clb.I1i clb.I2 clb.I2i clb.I3 clb.I3i</loc>
<loc side="right">clb.O[15:8] clb.I4 clb.I4i clb.I5 clb.I5i clb.I6 clb.I6i clb.I7 clb.I7i</loc>
<loc side="bottom">clb.reg_out clb.sc_out clb.cout</loc>
</pinlocations>
</tile>
<tile name="mult_16" height="2" area="396000">
<equivalent_sites>
<site pb_type="mult_16" pin_mapping="direct"/>
</equivalent_sites>
<input name="a" num_pins="16"/>
<input name="b" num_pins="16"/>
<output name="out" num_pins="32"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<!-- Highly recommand to customize pin location when direct connection is used!!! -->
<!--pinlocations pattern="spread"/-->
<pinlocations pattern="custom">
<loc side="left" yoffset="0">mult_16.a[0:2] mult_16.b[0:2] mult_16.out[0:5]</loc>
<loc side="left" yoffset="1">mult_16.a[3:5] mult_16.b[3:5] mult_16.out[6:10]</loc>
<loc side="top"></loc>
<loc side="right" yoffset="0">mult_16.a[8:10] mult_16.b[8:10] mult_16.out[16:21]</loc>
<loc side="right" yoffset="1">mult_16.a[11:13] mult_16.b[11:13] mult_16.out[22:26]</loc>
<loc side="bottom">mult_16.a[6:7] mult_16.b[6:7] mult_16.out[11:15] mult_16.a[14:15] mult_16.b[14:15] mult_16.out[27:31]</loc>
</pinlocations>
</tile>
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout tileable="true">
<auto_layout aspect_ratio="1.0">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
<!--Column of 'mult_8' with 'EMPTY' blocks wherever a 'mult_8' does not fit. Vertical offset by 1 for perimeter.-->
<col type="mult_16" startx="2" starty="1" repeatx="8" priority="20"/>
</auto_layout>
<fixed_layout name="3x4" width="5" height="6">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
<!--Column of 'mult_8' with 'EMPTY' blocks wherever a 'mult_8' does not fit. Vertical offset by 1 for perimeter.-->
<col type="mult_16" startx="2" starty="1" repeatx="8" priority="20"/>
</fixed_layout>
<fixed_layout name="12x12" width="14" height="14">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
<!--Column of 'mult_8' with 'EMPTY' blocks wherever a 'mult_8' does not fit. Vertical offset by 1 for perimeter.-->
<col type="mult_16" startx="2" starty="1" repeatx="8" priority="20"/>
</fixed_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" sub_type="subset" sub_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="L1_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="L2_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="L4_mux" 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="L1" freq="0.10" length="1" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L1_mux"/>
<sb type="pattern">1 1</sb>
<cb type="pattern">1</cb>
</segment>
<segment name="L2" freq="0.10" length="2" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L2_mux"/>
<sb type="pattern">1 1 1</sb>
<cb type="pattern">1 1</cb>
</segment>
<segment name="L4" freq="0.80" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L4_mux"/>
<sb type="pattern">1 1 1 1 1</sb>
<cb type="pattern">1 1 1 1</cb>
</segment>
</segmentlist>
<directlist>
<direct name="carry_chain" from_pin="clb.cout" to_pin="clb.cin" x_offset="0" y_offset="-1" z_offset="0"/>
<direct name="shift_register" from_pin="clb.reg_out" to_pin="clb.reg_in" x_offset="0" y_offset="-1" z_offset="0"/>
<direct name="scan_chain" from_pin="clb.sc_out" to_pin="clb.sc_in" x_offset="0" y_offset="-1" z_offset="0"/>
</directlist>
<complexblocklist>
<!-- Define input pads begin -->
<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" disable_packing="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>
<power method="ignore"/>
</pb_type>
<!-- Define I/O pads ends -->
<!-- Define general purpose logic block (CLB) begin -->
<!-- -Due to the absence of local routing,
the 4 inputs of fracturable LUT4 are no longer equivalent,
because the 4th input can not be switched when the dual-LUT3 modes are used.
So pin equivalence should be applied to the first 3 inputs only
-->
<pb_type name="clb">
<input name="I0" num_pins="2" equivalent="full"/>
<input name="I0i" num_pins="2" equivalent="none"/>
<input name="I1" num_pins="2" equivalent="full"/>
<input name="I1i" num_pins="2" equivalent="none"/>
<input name="I2" num_pins="2" equivalent="full"/>
<input name="I2i" num_pins="2" equivalent="none"/>
<input name="I3" num_pins="2" equivalent="full"/>
<input name="I3i" num_pins="2" equivalent="none"/>
<input name="I4" num_pins="2" equivalent="full"/>
<input name="I4i" num_pins="2" equivalent="none"/>
<input name="I5" num_pins="2" equivalent="full"/>
<input name="I5i" num_pins="2" equivalent="none"/>
<input name="I6" num_pins="2" equivalent="full"/>
<input name="I6i" num_pins="2" equivalent="none"/>
<input name="I7" num_pins="2" equivalent="full"/>
<input name="I7i" num_pins="2" equivalent="none"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1" is_non_clock_global="true"/>
<output name="O" num_pins="16" equivalent="none"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<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="8">
<input name="in" num_pins="4"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Physical mode definition begin (physical implementation of the fle) -->
<mode name="physical" disable_packing="true">
<pb_type name="fabric" num_pb="1">
<input name="in" num_pins="4"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<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="4"/>
<input name="cin" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="cout" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="frac_lut4" blif_model=".subckt frac_lut4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="lut2_out" num_pins="2"/>
<output name="lut3_out" num_pins="2"/>
<output name="lut4_out" num_pins="1"/>
</pb_type>
<pb_type name="carry_follower" blif_model=".subckt carry_follower_physical" 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"/>
<delay_constant max="0.3e-9" in_port="carry_follower.a" out_port="carry_follower.cout"/>
<delay_constant max="0.3e-9" in_port="carry_follower.b" out_port="carry_follower.cout"/>
<delay_constant max="0.3e-9" in_port="carry_follower.cin" out_port="carry_follower.cout"/>
</pb_type>
<interconnect>
<direct name="direct1" input="frac_logic.in[0:1]" output="frac_lut4.in[0:1]"/>
<direct name="direct2" input="frac_logic.in[3:3]" output="frac_lut4.in[3:3]"/>
<direct name="direct3" input="frac_logic.cin" output="carry_follower.b"/>
<direct name="direct4" input="frac_lut4.lut2_out[1:1]" output="carry_follower.a"/>
<direct name="direct5" input="frac_lut4.lut2_out[0:0]" output="carry_follower.cin"/>
<direct name="direct6" input="carry_follower.cout" output="frac_logic.cout"/>
<direct name="direct7" input="frac_lut4.lut3_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_lut4.lut4_out frac_lut4.lut3_out[0]" output="frac_logic.out[0]"/>
<mux name="mux2" input="frac_logic.cin frac_logic.in[2:2]" output="frac_lut4.in[2:2]"/>
</interconnect>
</pb_type>
<!-- Define flip-flop with scan-chain capability, DI is the scan-chain data input -->
<pb_type name="ff" blif_model=".subckt scff" num_pb="2">
<input name="D" num_pins="1"/>
<input name="DI" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="Q" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_setup value="66e-12" port="ff.DI" clock="clk"/>
<T_setup value="66e-12" port="ff.reset" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="fabric.in" output="frac_logic.in"/>
<direct name="direct2" input="fabric.cin" output="frac_logic.cin"/>
<direct name="direct3" input="fabric.sc_in" output="ff[0].DI"/>
<direct name="direct4" input="ff[0].Q" output="ff[1].DI"/>
<direct name="direct5" input="ff[1].Q" output="fabric.sc_out"/>
<direct name="direct6" input="ff[1].Q" output="fabric.reg_out"/>
<direct name="direct7" input="frac_logic.cout" output="fabric.cout"/>
<complete name="complete1" input="fabric.clk" output="ff[1:0].clk"/>
<complete name="complete2" input="fabric.reset" output="ff[1:0].reset"/>
<mux name="mux1" input="frac_logic.out[0:0] fabric.reg_in" output="ff[0:0].D">
<delay_constant max="25e-12" in_port="frac_logic.out[0:0]" out_port="ff[0:0].D"/>
<delay_constant max="45e-12" in_port="fabric.reg_in" out_port="ff[0:0].D"/>
</mux>
<mux name="mux2" input="frac_logic.out[1:1] ff[0:0].Q" output="ff[1:1].D">
<delay_constant max="25e-12" in_port="frac_logic.out[1:1]" out_port="ff[1:1].D"/>
<delay_constant max="45e-12" in_port="ff[0:0].Q" out_port="ff[1:1].D"/>
</mux>
<mux name="mux3" input="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="mux4" input="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.reg_in" output="fabric.reg_in"/>
<direct name="direct3" input="fle.sc_in" output="fabric.sc_in"/>
<direct name="direct4" input="fle.cin" output="fabric.cin"/>
<direct name="direct5" input="fabric.out" output="fle.out"/>
<direct name="direct6" input="fabric.reg_out" output="fle.reg_out"/>
<direct name="direct7" input="fabric.sc_out" output="fle.sc_out"/>
<direct name="direct8" input="fabric.cout" output="fle.cout"/>
<direct name="direct9" input="fle.clk" output="fabric.clk"/>
<direct name="direct10" input="fle.reset" output="fabric.reset"/>
</interconnect>
</mode>
<!-- Physical mode definition end (physical implementation of the fle) -->
<!-- Arithmetic mode definition begin -->
<mode name="arithmetic">
<pb_type name="soft_adder" num_pb="1">
<input name="in" num_pins="4"/>
<input name="cin" num_pins="1"/>
<output name="sumout" num_pins="1"/>
<output name="cout" num_pins="1"/>
<!-- Define special LUT marco to be used as adder -->
<pb_type name="adder_lut4" blif_model=".subckt adder_lut4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="lut2_out" num_pins="2"/>
<output name="lut4_out" num_pins="1"/>
<delay_constant max="0.3e-9" in_port="adder_lut4.in" out_port="adder_lut4.lut2_out"/>
<delay_constant max="0.3e-9" in_port="adder_lut4.in" out_port="adder_lut4.lut4_out"/>
</pb_type>
<pb_type name="carry_follower" blif_model=".subckt carry_follower" 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"/>
<delay_constant max="0.3e-9" in_port="carry_follower.a" out_port="carry_follower.cout"/>
<delay_constant max="0.3e-9" in_port="carry_follower.b" out_port="carry_follower.cout"/>
<delay_constant max="0.3e-9" in_port="carry_follower.cin" out_port="carry_follower.cout"/>
</pb_type>
<interconnect>
<direct name="direct1" input="soft_adder.in[0:1]" output="adder_lut4.in[0:1]"/>
<direct name="direct2" input="soft_adder.in[3:3]" output="adder_lut4.in[3:3]"/>
<direct name="direct3" input="soft_adder.cin" output="carry_follower.b">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="soft_adder.cin" out_port="carry_follower.b"/>
</direct>
<direct name="direct4" input="adder_lut4.lut2_out[1:1]" output="carry_follower.a">
<!-- Pack pattern to pair adder_lut4 and carry_follower into a molecule
considered by packer -->
<pack_pattern name="lut_follower" in_port="adder_lut4.lut2_out[1:1]" out_port="carry_follower.a"/>
</direct>
<direct name="direct5" input="adder_lut4.lut2_out[0:0]" output="carry_follower.cin">
</direct>
<direct name="direct6" input="carry_follower.cout" output="soft_adder.cout">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="carry_follower.cout" out_port="soft_adder.cout"/>
</direct>
<direct name="direct7" input="adder_lut4.lut4_out" output="soft_adder.sumout[0:0]">
</direct>
<mux name="mux1" input="soft_adder.cin soft_adder.in[2:2]" output="adder_lut4.in[2:2]">
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="soft_adder.in"/>
<direct name="direct2" input="fle.cin" output="soft_adder.cin">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="fle.cin" out_port="soft_adder.cin"/>
</direct>
<direct name="direct3" input="soft_adder.sumout" output="fle.out[0:0]"/>
<direct name="direct4" input="soft_adder.cout" output="fle.cout">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="soft_adder.cout" out_port="fle.cout"/>
</direct>
</interconnect>
</mode>
<!-- Arithmetic mode definition end -->
<!-- Dual 3-LUT mode definition begin -->
<mode name="n2_lut3">
<pb_type name="lut3inter" num_pb="1">
<input name="in" num_pins="3"/>
<output name="out" num_pins="2"/>
<clock name="clk" num_pins="1"/>
<pb_type name="ble3" num_pb="2">
<input name="in" num_pins="3"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define the LUT -->
<pb_type name="lut3" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="3" 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="lut3.in" out_port="lut3.out">
235e-12
235e-12
235e-12
</delay_matrix>
</pb_type>
<!-- Define the flip-flop -->
<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="ble3.in[2:0]" output="lut3[0:0].in[2:0]"/>
<direct name="direct2" input="lut3[0:0].out" output="ff[0:0].D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble3" in_port="lut3[0:0].out" out_port="ff[0:0].D"/>
</direct>
<direct name="direct3" input="ble3.clk" output="ff[0:0].clk"/>
<mux name="mux1" input="ff[0:0].Q lut3.out[0:0]" output="ble3.out[0:0]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut3.out[0:0]" out_port="ble3.out[0:0]"/>
<delay_constant max="45e-12" in_port="ff[0:0].Q" out_port="ble3.out[0:0]"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="lut3inter.in" output="ble3[0:0].in"/>
<direct name="direct2" input="lut3inter.in" output="ble3[1:1].in"/>
<direct name="direct3" input="ble3[1:0].out" output="lut3inter.out"/>
<complete name="complete1" input="lut3inter.clk" output="ble3[1:0].clk"/>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in[2:0]" output="lut3inter.in"/>
<direct name="direct2" input="lut3inter.out" output="fle.out"/>
<direct name="direct3" input="fle.clk" output="lut3inter.clk"/>
</interconnect>
</mode>
<!-- Dual 3-LUT mode definition end -->
<!-- 4-LUT mode definition begin -->
<mode name="n1_lut4">
<!-- Define 4-LUT mode -->
<pb_type name="ble4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="lut4" blif_model=".names" num_pb="1" 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
398e-12
397e-12
-->
<delay_matrix type="max" in_port="lut4.in" out_port="lut4.out">
261e-12
261e-12
261e-12
261e-12
</delay_matrix>
</pb_type>
<!-- Define flip-flop -->
<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="ble4.in" output="lut4[0:0].in"/>
<direct name="direct2" input="lut4.out" output="ff.D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble4" in_port="lut4.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble4.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut4.out" output="ble4.out">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut4.out" out_port="ble4.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble4.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="ble4.in"/>
<direct name="direct2" input="ble4.out" output="fle.out[0:0]"/>
<direct name="direct3" input="fle.clk" output="ble4.clk"/>
</interconnect>
</mode>
<!-- 4-LUT mode definition end -->
<!-- Define shift register begin -->
<mode name="shift_register">
<pb_type name="shift_reg" num_pb="1">
<input name="reg_in" num_pins="1"/>
<output name="ff_out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<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>
<interconnect>
<direct name="direct1" input="shift_reg.reg_in" output="ff[0].D"/>
<direct name="direct2" input="ff[0].Q" output="ff[1].D"/>
<direct name="direct3" input="ff[1].Q" output="shift_reg.reg_out"/>
<direct name="direct4" input="ff[0].Q" output="shift_reg.ff_out[0:0]"/>
<direct name="direct5" input="ff[1].Q" output="shift_reg.ff_out[1:1]"/>
<complete name="complete1" input="shift_reg.clk" output="ff.clk"/>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.reg_in" output="shift_reg.reg_in"/>
<direct name="direct2" input="shift_reg.reg_out" output="fle.reg_out"/>
<direct name="direct3" input="shift_reg.ff_out" output="fle.out"/>
<direct name="direct4" input="fle.clk" output="shift_reg.clk"/>
</interconnect>
</mode>
<!-- Define shift register end -->
</pb_type>
<interconnect>
<!-- We use direct connections to reduce the area to the most
The global local routing is going to compensate the loss in routability
-->
<!-- FIXME: The implicit port definition results in I0[0] connected to
in[2]. Such twisted connection is not expected.
I[0] should be connected to in[0]
-->
<direct name="direct_fle0" input="clb.I0[0:1]" output="fle[0:0].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle0i" input="clb.I0i[0:1]" output="fle[0:0].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle1" input="clb.I1[0:1]" output="fle[1:1].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle1i" input="clb.I1i[0:1]" output="fle[1:1].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle2" input="clb.I2[0:1]" output="fle[2:2].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle2i" input="clb.I2i[0:1]" output="fle[2:2].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle3" input="clb.I3[0:1]" output="fle[3:3].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle3i" input="clb.I3i[0:1]" output="fle[3:3].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle4" input="clb.I4[0:1]" output="fle[4:4].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle4i" input="clb.I4i[0:1]" output="fle[4:4].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle5" input="clb.I5[0:1]" output="fle[5:5].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle5i" input="clb.I5i[0:1]" output="fle[5:5].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle6" input="clb.I6[0:1]" output="fle[6:6].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle6i" input="clb.I6i[0:1]" output="fle[6:6].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle7" input="clb.I7[0:1]" output="fle[7:7].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle7i" input="clb.I7i[0:1]" output="fle[7:7].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<complete name="clks" input="clb.clk" output="fle[7:0].clk">
</complete>
<complete name="resets" input="clb.reset" output="fle[7:0].reset">
</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[3:0].out[0:1]" output="clb.O[7:0]"/>
<direct name="clbouts2" input="fle[7:4].out[0:1]" output="clb.O[15:8]"/>
<!-- Shift register chain links -->
<direct name="shift_register_in" input="clb.reg_in" output="fle[0:0].reg_in">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.reg_in" out_port="fle[0:0].reg_in"/>
<!--pack_pattern name="chain" in_port="clb.reg_in" out_port="fle[0:0].reg_in"/-->
</direct>
<direct name="shift_register_out" input="fle[7:7].reg_out" output="clb.reg_out">
<!--pack_pattern name="chain" in_port="fle[7:7].reg_out" out_port="clb.reg_out"/-->
</direct>
<direct name="shift_register_link" input="fle[6:0].reg_out" output="fle[7:1].reg_in">
<!--pack_pattern name="chain" in_port="fle[6:0].reg_out" out_port="fle[7:1].reg_in"/-->
</direct>
<!-- Scan chain links -->
<direct name="scan_chain_in" input="clb.sc_in" output="fle[0:0].sc_in">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.sc_in" out_port="fle[0:0].sc_in"/>
</direct>
<direct name="scan_chain_out" input="fle[7:7].sc_out" output="clb.sc_out">
</direct>
<direct name="scan_chain_link" input="fle[6:0].sc_out" output="fle[7:1].sc_in">
</direct>
<!-- Carry chain links -->
<direct name="carry_chain_in" input="clb.cin" output="fle[0:0].cin">
<!-- Put all inter-block carry chain delay on this one edge -->
<pack_pattern name="chain" in_port="clb.cin" out_port="fle[0:0].cin"/>
<delay_constant max="0.16e-9" in_port="clb.cin" out_port="fle[0:0].cin"/>
</direct>
<direct name="carry_chain_out" input="fle[7:7].cout" output="clb.cout">
<pack_pattern name="chain" in_port="fle[7:7].cout" out_port="clb.cout"/>
</direct>
<direct name="carry_chain_link" input="fle[6:0].cout" output="fle[7:1].cin">
<pack_pattern name="chain" in_port="fle[6:0].cout" out_port="fle[7:1].cin"/>
</direct>
</interconnect>
<!-- 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 -->
<!-- Place this general purpose logic block in any unspecified column -->
</pb_type>
<!-- Define general purpose logic block (CLB) ends -->
<!-- Define fracturable multiplier begin -->
<pb_type name="mult_16">
<input name="a" num_pins="16"/>
<input name="b" num_pins="16"/>
<output name="out" num_pins="32"/>
<mode name="mult_8x8">
<pb_type name="mult_8x8_slice" num_pb="2">
<input name="A_cfg" num_pins="8"/>
<input name="B_cfg" num_pins="8"/>
<output name="OUT_cfg" num_pins="16"/>
<pb_type name="mult_8x8" blif_model=".subckt mult_8" num_pb="1">
<input name="A" num_pins="8"/>
<input name="B" num_pins="8"/>
<output name="Y" num_pins="16"/>
<delay_constant max="1.523e-9" min="0.776e-9" in_port="mult_8x8.A" out_port="mult_8x8.Y"/>
<delay_constant max="1.523e-9" min="0.776e-9" in_port="mult_8x8.B" out_port="mult_8x8.Y"/>
</pb_type>
<interconnect>
<direct name="a2a" input="mult_8x8_slice.A_cfg" output="mult_8x8.A">
</direct>
<direct name="b2b" input="mult_8x8_slice.B_cfg" output="mult_8x8.B">
</direct>
<direct name="out2out" input="mult_8x8.Y" output="mult_8x8_slice.OUT_cfg">
</direct>
</interconnect>
<power method="pin-toggle">
<port name="A_cfg" energy_per_toggle="2.13e-12"/>
<port name="B_cfg" energy_per_toggle="2.13e-12"/>
<static_power power_per_instance="0.0"/>
</power>
</pb_type>
<interconnect>
<direct name="a2a_0" input="mult_16.a[0:7]" output="mult_8x8_slice[0].A_cfg[0:7]">
<delay_constant max="134e-12" min="74e-12" in_port="mult_16.a[0:7]" out_port="mult_8x8_slice[0].A_cfg[0:7]"/>
</direct>
<direct name="a2a_1" input="mult_16.a[8:15]" output="mult_8x8_slice[1].A_cfg[0:7]">
<delay_constant max="134e-12" min="74e-12" in_port="mult_16.a[8:15]" out_port="mult_8x8_slice[1].A_cfg[0:7]"/>
</direct>
<direct name="b2b_0" input="mult_16.b[0:7]" output="mult_8x8_slice[0].B_cfg[0:7]">
<delay_constant max="134e-12" min="74e-12" in_port="mult_16.b[0:7]" out_port="mult_8x8_slice[0].B_cfg[0:7]"/>
</direct>
<direct name="b2b_1" input="mult_16.b[8:15]" output="mult_8x8_slice[1].B_cfg[0:7]">
<delay_constant max="134e-12" min="74e-12" in_port="mult_16.b[8:15]" out_port="mult_8x8_slice[1].B_cfg[0:7]"/>
</direct>
<direct name="out2out_0" input="mult_8x8_slice[0].OUT_cfg[0:15]" output="mult_16.out[0:15]">
<delay_constant max="1.93e-9" min="74e-12" in_port="mult_8x8_slice[0].OUT_cfg[0:15]" out_port="mult_16.out[0:15]"/>
</direct>
<direct name="out2out_1" input="mult_8x8_slice[1].OUT_cfg[0:15]" output="mult_16.out[16:31]">
<delay_constant max="1.93e-9" min="74e-12" in_port="mult_8x8_slice[1].OUT_cfg[0:15]" out_port="mult_16.out[16:31]"/>
</direct>
</interconnect>
</mode>
<mode name="mult_16x16">
<pb_type name="mult_16x16_slice" num_pb="1">
<input name="A_cfg" num_pins="16"/>
<input name="B_cfg" num_pins="16"/>
<output name="OUT_cfg" num_pins="32"/>
<pb_type name="mult_16x16" blif_model=".subckt mult_16" num_pb="1">
<input name="A" num_pins="16"/>
<input name="B" num_pins="16"/>
<output name="Y" num_pins="32"/>
<delay_constant max="1.523e-9" min="0.776e-9" in_port="mult_16x16.A" out_port="mult_16x16.Y"/>
<delay_constant max="1.523e-9" min="0.776e-9" in_port="mult_16x16.B" out_port="mult_16x16.Y"/>
</pb_type>
<interconnect>
<direct name="a2a" input="mult_16x16_slice.A_cfg" output="mult_16x16.A">
</direct>
<direct name="b2b" input="mult_16x16_slice.B_cfg" output="mult_16x16.B">
</direct>
<direct name="out2out" input="mult_16x16.Y" output="mult_16x16_slice.OUT_cfg">
</direct>
</interconnect>
<power method="pin-toggle">
<port name="A_cfg" energy_per_toggle="2.13e-12"/>
<port name="B_cfg" energy_per_toggle="2.13e-12"/>
<static_power power_per_instance="0.0"/>
</power>
</pb_type>
<interconnect>
<direct name="a2a" input="mult_16.a" output="mult_16x16_slice.A_cfg">
<delay_constant max="134e-12" min="74e-12" in_port="mult_16.a" out_port="mult_16x16_slice.A_cfg"/>
</direct>
<direct name="b2b" input="mult_16.b" output="mult_16x16_slice.B_cfg">
<delay_constant max="134e-12" min="74e-12" in_port="mult_16.b" out_port="mult_16x16_slice.B_cfg"/>
</direct>
<direct name="out2out" input="mult_16x16_slice.OUT_cfg" output="mult_16.out">
<delay_constant max="1.93e-9" min="74e-12" in_port="mult_16x16_slice.OUT_cfg" out_port="mult_16.out"/>
</direct>
</interconnect>
</mode>
<!-- Place this multiplier block every 8 columns from (and including) the sixth column -->
<power method="sum-of-children"/>
</pb_type>
<!-- Define fracturable multiplier end -->
</complexblocklist>
</architecture>