From 836f722f2038cec4120900d8dfc1ec009e1341ac Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 5 Apr 2020 15:19:46 -0600 Subject: [PATCH] start supporting global output ports in module manager --- openfpga/src/fabric/module_manager.cpp | 2 +- openfpga/src/fabric/module_manager.h | 1 + .../src/fpga_verilog/verilog_writer_utils.cpp | 3 + openfpga/src/utils/module_manager_utils.cpp | 166 +++++++++++++++++- openfpga/src/utils/module_manager_utils.h | 6 + 5 files changed, 170 insertions(+), 8 deletions(-) diff --git a/openfpga/src/fabric/module_manager.cpp b/openfpga/src/fabric/module_manager.cpp index 40f672194..7f444318e 100644 --- a/openfpga/src/fabric/module_manager.cpp +++ b/openfpga/src/fabric/module_manager.cpp @@ -120,7 +120,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 MODULE_PORT_TYPE_STRING = {{"GLOBAL PORTS", "GPIO PORTS", "INOUT PORTS", "INPUT PORTS", "OUTPUT PORTS", "CLOCK PORTS"}}; + std::array MODULE_PORT_TYPE_STRING = {{"GLOBAL PORTS", "SPY PORTS", "GPIO PORTS", "INOUT PORTS", "INPUT PORTS", "OUTPUT PORTS", "CLOCK PORTS"}}; return MODULE_PORT_TYPE_STRING[port_type]; } diff --git a/openfpga/src/fabric/module_manager.h b/openfpga/src/fabric/module_manager.h index 425b7a072..1bfbd8b49 100644 --- a/openfpga/src/fabric/module_manager.h +++ b/openfpga/src/fabric/module_manager.h @@ -28,6 +28,7 @@ class ModuleManager { public: /* Private data structures */ enum e_module_port_type { MODULE_GLOBAL_PORT, /* Global inputs */ + MODULE_SPY_PORT, /* Global outputs, which is designed for spypads */ 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 */ diff --git a/openfpga/src/fpga_verilog/verilog_writer_utils.cpp b/openfpga/src/fpga_verilog/verilog_writer_utils.cpp index 95f34ab1f..b771f4752 100644 --- a/openfpga/src/fpga_verilog/verilog_writer_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_writer_utils.cpp @@ -129,6 +129,7 @@ void print_verilog_module_definition(std::fstream& fp, /* port type2type mapping */ std::map port_type2type_map; port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_CONKT; + port_type2type_map[ModuleManager::MODULE_SPY_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; @@ -188,6 +189,7 @@ void print_verilog_module_ports(std::fstream& fp, /* port type2type mapping */ std::map port_type2type_map; port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_INPUT; + port_type2type_map[ModuleManager::MODULE_SPY_PORT] = VERILOG_PORT_OUTPUT; port_type2type_map[ModuleManager::MODULE_GPIO_PORT] = VERILOG_PORT_INOUT; port_type2type_map[ModuleManager::MODULE_INOUT_PORT] = VERILOG_PORT_INOUT; port_type2type_map[ModuleManager::MODULE_INPUT_PORT] = VERILOG_PORT_INPUT; @@ -344,6 +346,7 @@ void print_verilog_module_instance(std::fstream& fp, /* port type2type mapping */ std::map port_type2type_map; port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_CONKT; + port_type2type_map[ModuleManager::MODULE_SPY_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; diff --git a/openfpga/src/utils/module_manager_utils.cpp b/openfpga/src/utils/module_manager_utils.cpp index 9797763b0..5c3f4a41b 100644 --- a/openfpga/src/utils/module_manager_utils.cpp +++ b/openfpga/src/utils/module_manager_utils.cpp @@ -36,10 +36,20 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager, VTR_ASSERT(ModuleId::INVALID() != module); /* Add ports */ - /* Find global ports and add one by one */ + /* Find global ports and add one by one + * Global input ports will be considered as global port in the context of module manager + * Global output ports will be considered as spy port in the context of module manager + */ for (const auto& port : circuit_lib.model_global_ports(circuit_model, false)) { BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); - module_manager.add_port(module, port_info, ModuleManager::MODULE_GLOBAL_PORT); + if (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) { + module_manager.add_port(module, port_info, ModuleManager::MODULE_GLOBAL_PORT); + } else if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(port)) { + module_manager.add_port(module, port_info, ModuleManager::MODULE_GLOBAL_PORT); + } else { + VTR_ASSERT(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)); + module_manager.add_port(module, port_info, ModuleManager::MODULE_SPY_PORT); + } } /* Find other ports and add one by one */ @@ -1011,18 +1021,30 @@ void add_module_gpio_ports_from_child_modules(ModuleManager& module_manager, } /******************************************************************** - * Add global ports to the module: + * Add global input 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 + * 1. find all the global input ports from the child modules and build a list of it, + * 2. add the input ports to the pb_module * 3. add the module nets to connect the pb_module global ports to those of child modules * + * Module + * +-------------------------- + * | child[0] + * input_portA[0] ----+-+---->+---------- + * | | | + * | | +---------- + * | | + * | | child[1] + * | +---->+---------- + * | | + * | +---------- + * * 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) { +void add_module_global_input_ports_from_child_modules(ModuleManager& module_manager, + const ModuleId& module_id) { std::vector global_ports_to_add; /* Iterate over the child modules */ @@ -1078,6 +1100,136 @@ void add_module_global_ports_from_child_modules(ModuleManager& module_manager, } } +/******************************************************************** + * Add global output ports to the module: + * In this function, the following tasks are done: + * 1. find all the global output ports from the child modules and build a list of it, + * 2. add the output ports to the pb_module + * 3. add the module nets to connect the pb_module global ports to those of child modules + * + * Module + * ----------------------+ + * | + * child[0] | + * -----------+ | + * |----------+----> outputA[0] + * -----------+ | + * | + * child[1] | + * -----------+ | + * |----------+----> outputA[1] + * -----------+ | + * + * 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_output_ports_from_child_modules(ModuleManager& module_manager, + const ModuleId& module_id) { + std::vector global_ports_to_add; + + /* Iterate over the child modules */ + for (const ModuleId& child : module_manager.child_modules(module_id)) { + /* Iterate over the child instances */ + for (size_t i = 0; i < module_manager.num_instance(module_id, child); ++i) { + /* Find all the global ports, whose port type is special */ + for (BasicPort global_port : module_manager.module_ports_by_type(child, ModuleManager::MODULE_SPY_PORT)) { + /* Search in the global port list to be added, if this is unique, we update the list */ + std::vector::iterator it = std::find(global_ports_to_add.begin(), global_ports_to_add.end(), global_port); + if (it != global_ports_to_add.end()) { + /* Found in the global port with the same name, increase the port size */ + it->expand(global_port.get_width()); + continue; /* Finish for the port already in the list */ + } + /* Reach here, this is an unique global port, update the list */ + global_ports_to_add.push_back(global_port); + } + } + } + + /* Record the port id for each type of global port */ + std::vector global_port_ids; + /* Add the global ports for the module */ + for (const BasicPort& global_port_to_add : global_ports_to_add) { + ModulePortId port_id = module_manager.add_port(module_id, global_port_to_add, ModuleManager::MODULE_SPY_PORT); + global_port_ids.push_back(port_id); + } + + /* Add module nets to connect the global ports of the module to the global ports of the sub module */ + /* Create a counter for each global port to record the current LSB */ + std::vector global_port_lsbs(global_port_ids.size(), 0); + + /* Iterate over the child modules */ + for (const ModuleId& child : module_manager.child_modules(module_id)) { + /* Iterate over the child instances */ + for (const size_t& child_instance : module_manager.child_module_instances(module_id, child)) { + /* Find all the global ports, whose port type is special */ + for (ModulePortId child_global_port_id : module_manager.module_port_ids_by_type(child, ModuleManager::MODULE_SPY_PORT)) { + /* Find the global port from the child module */ + BasicPort child_global_port = module_manager.module_port(child, child_global_port_id); + /* Search in the global port list to be added, find the port id */ + std::vector::iterator it = std::find(global_ports_to_add.begin(), global_ports_to_add.end(), child_global_port); + VTR_ASSERT(it != global_ports_to_add.end()); + + /* Find the global port from the parent module */ + size_t module_global_port_offset = it - global_ports_to_add.begin(); + ModulePortId module_global_port_id = global_port_ids[module_global_port_offset]; + BasicPort module_global_port = module_manager.module_port(module_id, module_global_port_id); + /* Current LSB should be in range */ + VTR_ASSERT(module_global_port.get_width() > global_port_lsbs[module_global_port_offset]); + /* Set the global port from the parent module as the LSB recorded */ + module_global_port.set_width(global_port_lsbs[module_global_port_offset], global_port_lsbs[module_global_port_offset]); + /* Update the LSB */ + global_port_lsbs[module_global_port_offset]++; + + /* The global ports should match in size */ + VTR_ASSERT(module_global_port.get_width() == child_global_port.get_width()); + /* For each pin of the child port, create a net and do wiring */ + for (size_t pin_id = 0; pin_id < child_global_port.pins().size(); ++pin_id) { + /* Reach here, it means this is the port we want, create a net and configure its source and sink */ + ModuleNetId net = module_manager.create_module_net(module_id); + module_manager.add_module_net_source(module_id, net, child, child_instance, child_global_port_id, child_global_port.pins()[pin_id]); + module_manager.add_module_net_sink(module_id, net, module_id, 0, module_global_port_id, module_global_port.pins()[pin_id]); + /* We finish for this child gpio port */ + } + } + } + } + + /* Find check: all the LSBs of global ports should match the MSB */ + for (size_t iport = 0; iport < global_port_ids.size(); ++iport) { + BasicPort module_global_port = module_manager.module_port(module_id, global_port_ids[iport]); + VTR_ASSERT(module_global_port.get_width() == global_port_lsbs[iport]); + } +} + +/******************************************************************** + * Add global ports to the module: + * In this function, we will add global input ports and global output ports + * which are collected from the child modules + * + * - Input ports: the input ports will be uniquified by names + * Ports with the same name will be merged to the same pin + * See details inside the function + * + * - Output ports: the output ports will be uniquified by names + * Different from the input ports, output ports + * with the same name will be merged but will have indepedent pins + * See details inside the function + * + * 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) { + /* Input ports */ + add_module_global_input_ports_from_child_modules(module_manager, module_id); + + /* Output ports */ + add_module_global_output_ports_from_child_modules(module_manager, module_id); +} + /******************************************************************** * Find the number of shared configuration bits for a module * by selected the maximum number of shared configuration bits of child modules diff --git a/openfpga/src/utils/module_manager_utils.h b/openfpga/src/utils/module_manager_utils.h index 6198701ad..fcc95b8ba 100644 --- a/openfpga/src/utils/module_manager_utils.h +++ b/openfpga/src/utils/module_manager_utils.h @@ -108,6 +108,12 @@ size_t find_module_num_config_bits(const ModuleManager& module_manager, const CircuitModelId& sram_model, const e_config_protocol_type& sram_orgz_type); +void add_module_global_input_ports_from_child_modules(ModuleManager& module_manager, + const ModuleId& module_id); + +void add_module_global_output_ports_from_child_modules(ModuleManager& module_manager, + const ModuleId& module_id); + void add_module_global_ports_from_child_modules(ModuleManager& module_manager, const ModuleId& module_id);