add gpio ports to pb_type modules

This commit is contained in:
tangxifan 2019-10-13 16:23:22 -06:00
parent 0f50251b3b
commit cab4bd6807
9 changed files with 208 additions and 12 deletions

View File

@ -83,6 +83,34 @@ std::vector<size_t> BasicPort::pins() const {
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) {
@ -218,6 +246,28 @@ void BasicPort::combine(const BasicPort& port) {
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 */

View File

@ -17,6 +17,8 @@ class BasicPort {
BasicPort(const std::string& name, const size_t& lsb, const size_t& msb);
BasicPort(const std::string& name, const size_t& width);
BasicPort(const BasicPort& basic_port); /* Copy constructor */
public: /* Overloaded operators */
bool operator== (const BasicPort& portA) const;
public: /* Accessors */
size_t get_width() const; /* get the port width */
size_t get_msb() const; /* get the LSB */
@ -24,6 +26,8 @@ class BasicPort {
std::string get_name() const; /* get the name */
bool is_valid() const; /* check if port size is valid > 0 */
std::vector<size_t> pins() const; /* Make a range of the pin indices */
bool mergeable(const BasicPort& portA) const; /* Check if a port can be merged with this port */
bool contained(const BasicPort& portA) const; /* Check if a port is contained by this port */
public: /* Mutators */
void set(const BasicPort& basic_port); /* copy */
void set_name(const std::string& name); /* set the port LSB and MSB */
@ -37,6 +41,7 @@ class BasicPort {
bool counter_rotate(const size_t& offset); /* counter rotate */
void reset(); /* Reset to initial port */
void combine(const BasicPort& port); /* Combine two ports */
void merge(const BasicPort& portA);
private: /* internal functions */
void make_invalid(); /* Make a port invalid */
private: /* Internal Data */

View File

@ -21,6 +21,13 @@ ModuleManager::module_range ModuleManager::modules() const {
return vtr::make_range(ids_.begin(), ids_.end());
}
/* Find all the ports belonging to a module */
ModuleManager::module_port_range ModuleManager::module_ports(const ModuleId& module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(module));
return vtr::make_range(port_ids_[module].begin(), port_ids_[module].end());
}
/* Find all the nets belonging to a module */
ModuleManager::module_net_range ModuleManager::module_nets(const ModuleId& module) const {
/* Validate the module_id */
@ -94,7 +101,7 @@ std::string ModuleManager::module_name(const ModuleId& module_id) const {
/* Get the string of a module port type */
std::string ModuleManager::module_port_type_str(const enum e_module_port_type& port_type) const {
std::array<const char*, NUM_MODULE_PORT_TYPES> MODULE_PORT_TYPE_STRING = {{"GLOBAL PORTS", "INOUT PORTS", "INPUT PORTS", "OUTPUT PORTS", "CLOCK PORTS"}};
std::array<const char*, NUM_MODULE_PORT_TYPES> MODULE_PORT_TYPE_STRING = {{"GLOBAL PORTS", "GPIO PORTS", "INOUT PORTS", "INPUT PORTS", "OUTPUT PORTS", "CLOCK PORTS"}};
return MODULE_PORT_TYPE_STRING[port_type];
}

View File

@ -25,11 +25,12 @@
class ModuleManager {
public: /* Private data structures */
enum e_module_port_type {
MODULE_GLOBAL_PORT,
MODULE_INOUT_PORT,
MODULE_INPUT_PORT,
MODULE_OUTPUT_PORT,
MODULE_CLOCK_PORT,
MODULE_GLOBAL_PORT, /* Global inputs */
MODULE_GPIO_PORT, /* General-purpose IOs, which are data IOs of the fabric */
MODULE_INOUT_PORT, /* Normal (non-global) inout ports */
MODULE_INPUT_PORT, /* Normal (non-global) input ports */
MODULE_OUTPUT_PORT, /* Normal (non-global) output ports */
MODULE_CLOCK_PORT, /* Nromal (non-global) clock ports*/
NUM_MODULE_PORT_TYPES
};
@ -37,11 +38,13 @@ class ModuleManager {
public: /* Types and ranges */
typedef vtr::vector<ModuleId, ModuleId>::const_iterator module_iterator;
typedef vtr::vector<ModulePortId, ModulePortId>::const_iterator module_port_iterator;
typedef vtr::vector<ModuleNetId, ModuleNetId>::const_iterator module_net_iterator;
typedef vtr::vector<ModuleNetSrcId, ModuleNetSrcId>::const_iterator module_net_src_iterator;
typedef vtr::vector<ModuleNetSinkId, ModuleNetSinkId>::const_iterator module_net_sink_iterator;
typedef vtr::Range<module_iterator> module_range;
typedef vtr::Range<module_port_iterator> module_port_range;
typedef vtr::Range<module_net_iterator> module_net_range;
typedef vtr::Range<module_net_src_iterator> module_net_src_range;
typedef vtr::Range<module_net_sink_iterator> module_net_sink_range;
@ -49,6 +52,8 @@ class ModuleManager {
public: /* Public aggregators */
/* Find all the modules */
module_range modules() const;
/* Find all the ports belonging to a module */
module_port_range module_ports(const ModuleId& module) const;
/* Find all the nets belonging to a module */
module_net_range module_nets(const ModuleId& module) const;
/* Find all the child modules under a parent module */

View File

@ -840,6 +840,83 @@ size_t find_module_num_config_bits(const ModuleManager& module_manager,
return num_config_bits;
}
/********************************************************************
* Add global ports to the module:
* In this function, the following tasks are done:
* 1. find all the GPIO ports from the child modules and build a list of it,
* 2. Merge all the GPIO ports with the same name
* 3. add the ports to the pb_module
*
* Note: This function should be call ONLY after all the sub modules (instances)
* have been added to the pb_module!
* Otherwise, some GPIO ports of the sub modules may be missed!
*******************************************************************/
void add_module_gpio_ports_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id) {
std::vector<BasicPort> gpio_ports_to_add;
/* Iterate over the child modules */
for (const ModuleId& child : module_manager.child_modules(module_id)) {
/* Find all the global ports, whose port type is special */
for (BasicPort gpio_port : module_manager.module_ports_by_type(child, ModuleManager::MODULE_GPIO_PORT)) {
/* If this port is not mergeable, we update the list */
bool is_mergeable = false;
for (BasicPort& gpio_port_to_add : gpio_ports_to_add) {
if (false == gpio_port_to_add.mergeable(gpio_port)) {
continue;
}
is_mergeable = true;
/* For mergeable ports, we do a strong merge */
gpio_port_to_add.merge(gpio_port);
break;
}
if (false == is_mergeable) {
/* Reach here, this is an unique gpio port, update the list */
gpio_ports_to_add.push_back(gpio_port);
}
}
}
/* Add the gpio ports for the module */
for (const BasicPort& gpio_port_to_add : gpio_ports_to_add) {
module_manager.add_port(module_id, gpio_port_to_add, ModuleManager::MODULE_GPIO_PORT);
}
}
/********************************************************************
* Add GPIO ports to the module:
* In this function, the following tasks are done:
* 1. find all the global ports from the child modules and build a list of it,
* 2. add the ports to the pb_module
*
* Note: This function should be call ONLY after all the sub modules (instances)
* have been added to the pb_module!
* Otherwise, some global ports of the sub modules may be missed!
*******************************************************************/
void add_module_global_ports_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id) {
std::vector<BasicPort> global_ports_to_add;
/* Iterate over the child modules */
for (const ModuleId& child : module_manager.child_modules(module_id)) {
/* Find all the global ports, whose port type is special */
for (BasicPort global_port : module_manager.module_ports_by_type(child, ModuleManager::MODULE_GLOBAL_PORT)) {
/* Search in the global port list to be added, if this is unique, we update the list */
std::vector<BasicPort>::iterator it = std::find(global_ports_to_add.begin(), global_ports_to_add.end(), global_port);
if (it != global_ports_to_add.end()) {
continue;
}
/* Reach here, this is an unique global port, update the list */
global_ports_to_add.push_back(global_port);
}
}
/* Add the global ports for the module */
for (const BasicPort& global_port_to_add : global_ports_to_add) {
module_manager.add_port(module_id, global_port_to_add, ModuleManager::MODULE_GLOBAL_PORT);
}
}
/********************************************************************
* TODO:

View File

@ -82,4 +82,10 @@ size_t find_module_num_config_bits(const ModuleManager& module_manager,
const CircuitModelId& sram_model,
const e_sram_orgz& sram_orgz_type);
void add_module_global_ports_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id);
void add_module_gpio_ports_from_child_modules(ModuleManager& module_manager,
const ModuleId& module_id);
#endif

View File

@ -30,6 +30,7 @@
#include "verilog_module_writer.h"
#include "verilog_grid.h"
/********************************************************************
* Print Verilog modules of a primitive node in the pb_graph_node graph
* This generic function can support all the different types of primitive nodes
@ -108,7 +109,7 @@ void print_verilog_primitive_block(std::fstream& fp,
std::vector<CircuitPortId> primitive_model_inout_ports = circuit_lib.model_ports_by_type(primitive_model, SPICE_MODEL_PORT_INOUT);
for (auto port : primitive_model_inout_ports) {
BasicPort module_port(generate_fpga_global_io_port_name(std::string(gio_inout_prefix), circuit_lib, primitive_model), circuit_lib.port_size(port));
module_manager.add_port(primitive_module, module_port, ModuleManager::MODULE_INOUT_PORT);
module_manager.add_port(primitive_module, module_port, ModuleManager::MODULE_GPIO_PORT);
}
}
/* Note: to cooperate with the pb_type hierarchy and connections, we add the port of primitive pb_type here.
@ -627,7 +628,6 @@ void add_module_pb_graph_interc(ModuleManager& module_manager,
}
}
/********************************************************************
* Print Verilog modules of physical blocks inside a grid (CLB, I/O. etc.)
* This function will traverse the graph of complex logic block (t_pb_graph_node)
@ -763,15 +763,17 @@ void print_verilog_physical_blocks_rec(std::fstream& fp,
pb_module_name_prefix,
physical_mode_index);
/* TODO: Add global ports to the pb_module:
/* Add global ports to the pb_module:
* This is a much easier job after adding sub modules (instances),
* we just need to find all the global ports from the child modules and build a list of it
*/
add_module_global_ports_from_child_modules(module_manager, pb_module);
/* TODO: Count I/O (INOUT) ports from the sub-modules under this Verilog module
/* Count GPIO ports from the sub-modules under this Verilog module
* This is a much easier job after adding sub modules (instances),
* we just need to find all the I/O ports from the child modules and build a list of it
*/
add_module_gpio_ports_from_child_modules(module_manager, pb_module);
/* TODO: Count shared SRAM ports from the sub-modules under this Verilog module
* This is a much easier job after adding sub modules (instances),
@ -785,7 +787,6 @@ void print_verilog_physical_blocks_rec(std::fstream& fp,
/* TODO: Add module nets to connect memory cells inside */
/* Comment lines */
print_verilog_comment(fp, std::string("----- BEGIN Physical programmable logic block Verilog module: " + std::string(physical_pb_type->name) + " -----"));

View File

@ -7,12 +7,24 @@
* You should NOT modify any content of the module manager
* Please use const keyword to restrict this!
*******************************************************************/
#include <algorithm>
#include "vtr_assert.h"
#include "fpga_x2p_utils.h"
#include "module_manager_utils.h"
#include "verilog_writer_utils.h"
#include "verilog_module_writer.h"
/********************************************************************
* Generate the name of a local wire for a undriven port inside Verilog
* module
*******************************************************************/
static
std::string generate_verilog_undriven_local_wire_name(const ModuleManager& module_manager,
const ModuleId& module,
const ModulePortId& module_port_id) {
return module_manager.module_port(module, module_port_id).get_name();
}
/********************************************************************
* Name a net for a local wire for a verilog module
* 1. If this is a local wire, name it after the <src_module_name>_<instance_id>_<src_port_name>
@ -113,6 +125,36 @@ std::vector<BasicPort> find_verilog_module_local_wires(const ModuleManager& modu
}
}
/* Local wires could also happen for undriven ports of child module */
for (const ModuleId& child : module_manager.child_modules(module_id)) {
for (size_t instance : module_manager.child_module_instances(module_id, child)) {
for (const ModulePortId& child_port_id : module_manager.module_ports(child)) {
BasicPort child_port = module_manager.module_port(child, child_port_id);
std::vector<size_t> undriven_pins;
for (size_t child_pin : child_port.pins()) {
/* Find the net linked to the pin */
ModuleNetId net = module_manager.module_instance_port_net(module_id, child, instance,
child_port_id, child_pin);
/* We only care undriven ports */
if (ModuleNetId::INVALID() == net) {
undriven_pins.push_back(child_pin);
}
}
if (true == undriven_pins.empty()) {
continue;
}
/* Reach here, we need a local wire, we will create a port only for the undriven pins of the port! */
BasicPort instance_port;
instance_port.set_name(generate_verilog_undriven_local_wire_name(module_manager, child, child_port_id));
/* We give the same port name as child module, this case happens to global ports */
instance_port.set_width(*std::min_element(undriven_pins.begin(), undriven_pins.end()),
*std::max_element(undriven_pins.begin(), undriven_pins.end()));
local_wires.push_back(instance_port);
}
}
}
return local_wires;
}
@ -225,6 +267,7 @@ void write_verilog_instance_to_file(std::fstream& fp,
/* port type2type mapping */
std::map<ModuleManager::e_module_port_type, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_GPIO_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_INOUT_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_INPUT_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_OUTPUT_PORT] = VERILOG_PORT_CONKT;
@ -255,7 +298,7 @@ void write_verilog_instance_to_file(std::fstream& fp,
BasicPort instance_port;
if (ModuleNetId::INVALID() == net) {
/* We give the same port name as child module, this case happens to global ports */
instance_port.set_name(module_manager.module_port(child_module, child_port_id).get_name());
instance_port.set_name(generate_verilog_undriven_local_wire_name(module_manager, child_module, child_port_id));
instance_port.set_width(child_pin, child_pin);
} else {
/* Find the name for this child port */

View File

@ -108,6 +108,7 @@ void print_verilog_module_definition(std::fstream& fp,
/* port type2type mapping */
std::map<ModuleManager::e_module_port_type, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_GPIO_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_INOUT_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_INPUT_PORT] = VERILOG_PORT_CONKT;
port_type2type_map[ModuleManager::MODULE_OUTPUT_PORT] = VERILOG_PORT_CONKT;
@ -166,6 +167,7 @@ void print_verilog_module_ports(std::fstream& fp,
/* port type2type mapping */
std::map<ModuleManager::e_module_port_type, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_INPUT;
port_type2type_map[ModuleManager::MODULE_GPIO_PORT] = VERILOG_PORT_INPUT;
port_type2type_map[ModuleManager::MODULE_INOUT_PORT] = VERILOG_PORT_INOUT;
port_type2type_map[ModuleManager::MODULE_INPUT_PORT] = VERILOG_PORT_INPUT;
port_type2type_map[ModuleManager::MODULE_OUTPUT_PORT] = VERILOG_PORT_OUTPUT;