398 lines
8.9 KiB
C++
398 lines
8.9 KiB
C++
#include <numeric>
|
|
#include <algorithm>
|
|
#include <limits>
|
|
|
|
#include "vtr_assert.h"
|
|
|
|
#include "device_port.h"
|
|
|
|
/* Basic Port member functions */
|
|
/* Constructor */
|
|
/* Default constructor */
|
|
BasicPort::BasicPort() {
|
|
/* By default we set an invalid port, which size is 0 */
|
|
lsb_ = 1;
|
|
msb_ = 0;
|
|
}
|
|
|
|
/* Quick constructor */
|
|
BasicPort::BasicPort(const char* name, const size_t& lsb, const size_t& msb) {
|
|
set_name(std::string(name));
|
|
set_width(lsb, msb);
|
|
}
|
|
|
|
BasicPort::BasicPort(const std::string& name, const size_t& lsb, const size_t& msb) {
|
|
set_name(name);
|
|
set_width(lsb, msb);
|
|
}
|
|
|
|
BasicPort::BasicPort(const char* name, const size_t& width) {
|
|
set_name(std::string(name));
|
|
set_width(width);
|
|
}
|
|
|
|
BasicPort::BasicPort(const std::string& name, const size_t& width) {
|
|
set_name(name);
|
|
set_width(width);
|
|
}
|
|
|
|
/* Copy constructor */
|
|
BasicPort::BasicPort(const BasicPort& basic_port) {
|
|
set(basic_port);
|
|
}
|
|
|
|
/* Accessors */
|
|
/* get the port width */
|
|
size_t BasicPort::get_width() const {
|
|
if (true == is_valid()) {
|
|
return msb_ - lsb_ + 1;
|
|
}
|
|
return 0; /* invalid port has a zero width */
|
|
}
|
|
|
|
/* get the LSB */
|
|
size_t BasicPort::get_msb() const {
|
|
return msb_;
|
|
}
|
|
|
|
/* get the LSB */
|
|
size_t BasicPort::get_lsb() const {
|
|
return lsb_;
|
|
}
|
|
|
|
/* get the name */
|
|
std::string BasicPort::get_name() const {
|
|
return name_;
|
|
}
|
|
|
|
/* Make a range of the pin indices */
|
|
std::vector<size_t> BasicPort::pins() const {
|
|
std::vector<size_t> pin_indices;
|
|
|
|
/* Return if the port is invalid */
|
|
if (false == is_valid()) {
|
|
return pin_indices; /* Return an empty vector */
|
|
}
|
|
/* For valid ports, create a vector whose length is the port width */
|
|
pin_indices.resize(get_width());
|
|
/* Fill in an incremental sequence */
|
|
std::iota(pin_indices.begin(), pin_indices.end(), get_lsb());
|
|
/* Ensure the last one is MSB */
|
|
VTR_ASSERT(get_msb() == pin_indices.back());
|
|
|
|
return pin_indices;
|
|
}
|
|
|
|
/* Check if a port can be merged with this port: their name should be the same */
|
|
bool BasicPort::mergeable(const BasicPort& portA) const {
|
|
return (0 == this->get_name().compare(portA.get_name()));
|
|
}
|
|
|
|
/* Check if a port is contained by this port:
|
|
* this function will check if the (LSB, MSB) of portA
|
|
* is contained by the (LSB, MSB) of this port
|
|
*/
|
|
bool BasicPort::contained(const BasicPort& portA) const {
|
|
return ( lsb_ <= portA.get_lsb() && portA.get_msb() <= msb_ );
|
|
}
|
|
|
|
/* Overloaded operators */
|
|
/* Two ports are the same only when:
|
|
* 1. port names are the same
|
|
* 2. LSBs are the same
|
|
* 3. MSBs are the same
|
|
*/
|
|
bool BasicPort::operator== (const BasicPort& portA) const {
|
|
if ( (0 == this->get_name().compare(portA.get_name()))
|
|
&& (this->get_lsb() == portA.get_lsb())
|
|
&& (this->get_msb() == portA.get_msb()) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Mutators */
|
|
/* copy */
|
|
void BasicPort::set(const BasicPort& basic_port) {
|
|
name_ = basic_port.get_name();
|
|
lsb_ = basic_port.get_lsb();
|
|
msb_ = basic_port.get_msb();
|
|
|
|
return;
|
|
}
|
|
|
|
/* set the port LSB and MSB */
|
|
void BasicPort::set_name(const std::string& name) {
|
|
name_ = name;
|
|
return;
|
|
}
|
|
|
|
/* set the port LSB and MSB */
|
|
void BasicPort::set_width(const size_t& width) {
|
|
if (0 == width) {
|
|
make_invalid();
|
|
return;
|
|
}
|
|
lsb_ = 0;
|
|
msb_ = width - 1;
|
|
return;
|
|
}
|
|
|
|
/* set the port LSB and MSB */
|
|
void BasicPort::set_width(const size_t& lsb, const size_t& msb) {
|
|
/* If lsb and msb is invalid, we make a default port */
|
|
if (lsb > msb) {
|
|
make_invalid();
|
|
return;
|
|
}
|
|
set_lsb(lsb);
|
|
set_msb(msb);
|
|
return;
|
|
}
|
|
|
|
void BasicPort::set_lsb(const size_t& lsb) {
|
|
lsb_ = lsb;
|
|
return;
|
|
}
|
|
|
|
void BasicPort::set_msb(const size_t& msb) {
|
|
msb_ = msb;
|
|
return;
|
|
}
|
|
|
|
/* Increase the port width */
|
|
void BasicPort::expand(const size_t& width) {
|
|
if (0 == width) {
|
|
return; /* ignore zero-width port */
|
|
}
|
|
/* If current port is invalid, we do not combine */
|
|
if (0 == get_width()) {
|
|
lsb_ = 0;
|
|
msb_ = width;
|
|
return;
|
|
}
|
|
/* Increase MSB */
|
|
msb_ += width;
|
|
return;
|
|
}
|
|
|
|
/* Swap lsb and msb */
|
|
void BasicPort::revert() {
|
|
std::swap(lsb_, msb_);
|
|
return;
|
|
}
|
|
|
|
/* rotate: increase both lsb and msb by an offset */
|
|
bool BasicPort::rotate(const size_t& offset) {
|
|
/* If offset is 0, we do nothing */
|
|
if (0 == offset) {
|
|
return true;
|
|
}
|
|
|
|
/* If current width is 0, we set a width using the offset! */
|
|
if (0 == get_width()) {
|
|
set_width(offset);
|
|
return true;
|
|
}
|
|
/* check if leads to overflow:
|
|
* if limits - msb is larger than offset
|
|
*/
|
|
if ( (std::numeric_limits<size_t>::max() - msb_ < offset) ) {
|
|
return false;
|
|
}
|
|
/* Increase LSB and MSB */
|
|
lsb_ += offset;
|
|
msb_ += offset;
|
|
return true;
|
|
}
|
|
|
|
/* rotate: decrease both lsb and msb by an offset */
|
|
bool BasicPort::counter_rotate(const size_t& offset) {
|
|
/* If current port is invalid or offset is 0,
|
|
* we do nothing
|
|
*/
|
|
if ((0 == offset) || (0 == get_width())) {
|
|
return true;
|
|
}
|
|
/* check if leads to overflow:
|
|
* if limits is larger than offset
|
|
*/
|
|
if ( (std::numeric_limits<size_t>::min() + lsb_ < offset) ) {
|
|
return false;
|
|
}
|
|
/* decrease LSB and MSB */
|
|
lsb_ -= offset;
|
|
msb_ -= offset;
|
|
return true;
|
|
}
|
|
|
|
/* Reset to initial port */
|
|
void BasicPort::reset() {
|
|
make_invalid();
|
|
return;
|
|
}
|
|
|
|
/* Combine two ports */
|
|
void BasicPort::combine(const BasicPort& port) {
|
|
/* LSB follows the current LSB */
|
|
/* MSB increases */
|
|
VTR_ASSERT(0 < port.get_width() ); /* Make sure port is valid */
|
|
/* If current port is invalid, we do not combine */
|
|
if (0 == get_width()) {
|
|
return;
|
|
}
|
|
/* Increase MSB */
|
|
msb_ += port.get_width();
|
|
return;
|
|
}
|
|
|
|
/* A restricted combine function for two ports,
|
|
* Following conditions will be applied:
|
|
* 1. the two ports have the same name
|
|
* Note: you must run mergable() function first
|
|
* to make sure this assumption is valid
|
|
* 2. the new MSB will be the maximum MSB of the two ports
|
|
* 3. the new LSB will be the minimum LSB of the two ports
|
|
* 4. both ports should be valid!!!
|
|
*/
|
|
void BasicPort::merge(const BasicPort& portA) {
|
|
VTR_ASSERT(true == this->mergeable(portA));
|
|
VTR_ASSERT(true == this->is_valid() && true == portA.is_valid());
|
|
/* We skip merging if the portA is already contained by this port */
|
|
if (true == this->contained(portA)) {
|
|
return;
|
|
}
|
|
/* LSB follows the minium LSB of the two ports */
|
|
lsb_ = std::min((int)lsb_, (int)portA.get_lsb());
|
|
/* MSB follows the minium MSB of the two ports */
|
|
msb_ = std::max((int)msb_, (int)portA.get_msb());
|
|
return;
|
|
}
|
|
|
|
/* Internal functions */
|
|
/* Make a port to be invalid: msb < lsb */
|
|
void BasicPort::make_invalid() {
|
|
/* set a default invalid port */
|
|
lsb_ = 1;
|
|
msb_ = 0;
|
|
return;
|
|
}
|
|
|
|
/* check if port size is valid > 0 */
|
|
bool BasicPort::is_valid() const {
|
|
/* msb should be equal or greater than lsb, if this is a valid port */
|
|
if ( msb_ < lsb_ ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* ConfPorts member functions */
|
|
/* Constructor */
|
|
/* Default constructor */
|
|
ConfPorts::ConfPorts() {
|
|
/* default port */
|
|
reserved_.reset();
|
|
regular_.reset();
|
|
}
|
|
|
|
/* copy */
|
|
ConfPorts::ConfPorts(const ConfPorts& conf_ports) {
|
|
set(conf_ports);
|
|
}
|
|
|
|
/* Accessors */
|
|
size_t ConfPorts::get_reserved_port_width() const {
|
|
return reserved_.get_width();
|
|
}
|
|
|
|
size_t ConfPorts::get_reserved_port_lsb() const {
|
|
return reserved_.get_lsb();
|
|
}
|
|
|
|
size_t ConfPorts::get_reserved_port_msb() const {
|
|
return reserved_.get_msb();
|
|
}
|
|
|
|
size_t ConfPorts::get_regular_port_width() const {
|
|
return regular_.get_width();
|
|
}
|
|
|
|
size_t ConfPorts::get_regular_port_lsb() const {
|
|
return regular_.get_lsb();
|
|
}
|
|
|
|
size_t ConfPorts::get_regular_port_msb() const {
|
|
return regular_.get_msb();
|
|
}
|
|
|
|
/* Mutators */
|
|
void ConfPorts::set(const ConfPorts& conf_ports) {
|
|
set_reserved_port(conf_ports.get_reserved_port_width());
|
|
set_regular_port(conf_ports.get_regular_port_lsb(), conf_ports.get_regular_port_msb());
|
|
return;
|
|
}
|
|
|
|
void ConfPorts::set_reserved_port(size_t width) {
|
|
reserved_.set_width(width);
|
|
return;
|
|
}
|
|
|
|
void ConfPorts::set_regular_port(size_t width) {
|
|
regular_.set_width(width);
|
|
return;
|
|
}
|
|
|
|
void ConfPorts::set_regular_port(size_t lsb, size_t msb) {
|
|
regular_.set_width(lsb, msb);
|
|
return;
|
|
}
|
|
|
|
void ConfPorts::set_regular_port_lsb(size_t lsb) {
|
|
regular_.set_lsb(lsb);
|
|
return;
|
|
}
|
|
|
|
void ConfPorts::set_regular_port_msb(size_t msb) {
|
|
regular_.set_msb(msb);
|
|
return;
|
|
}
|
|
|
|
/* Increase the port width of reserved port */
|
|
void ConfPorts::expand_reserved_port(size_t width) {
|
|
reserved_.expand(width);
|
|
return;
|
|
}
|
|
|
|
/* Increase the port width of regular port */
|
|
void ConfPorts::expand_regular_port(size_t width) {
|
|
regular_.expand(width);
|
|
return;
|
|
}
|
|
|
|
/* Increase the port width of both ports */
|
|
void ConfPorts::expand(size_t width) {
|
|
expand_reserved_port(width);
|
|
expand_regular_port(width);
|
|
}
|
|
|
|
/* rotate */
|
|
bool ConfPorts::rotate_regular_port(size_t offset) {
|
|
return regular_.rotate(offset);
|
|
}
|
|
|
|
/* counter rotate */
|
|
bool ConfPorts::counter_rotate_regular_port(size_t offset) {
|
|
return regular_.counter_rotate(offset);
|
|
}
|
|
|
|
/* Reset to initial port */
|
|
void ConfPorts::reset() {
|
|
reserved_.reset();
|
|
regular_.reset();
|
|
return;
|
|
}
|
|
|
|
|
|
|