add gpio ports to pb_type modules
This commit is contained in:
parent
0f50251b3b
commit
cab4bd6807
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) + " -----"));
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue