Refactoring Verilog generation intermediate level of pb_types and SRAM port generation

This commit is contained in:
tangxifan 2019-10-11 21:43:47 -06:00
parent b3ca0d32a4
commit d1948c82eb
6 changed files with 248 additions and 81 deletions

View File

@ -295,3 +295,104 @@ bool check_mem_config_bus(const e_sram_orgz& sram_orgz_type,
/* Reach here, it means something goes wrong, return a false value */
return false;
}
/********************************************************************
* Generate a list of ports that are used for SRAM configuration to a module
* The type and names of added ports strongly depend on the
* organization of SRAMs.
* 1. Standalone SRAMs:
* two ports will be added, which are regular output and inverted output
* 2. Scan-chain Flip-flops:
* two ports will be added, which are the head of scan-chain
* and the tail of scan-chain
* IMPORTANT: the port size will be forced to 1 in this case
* because the head and tail are both 1-bit ports!!!
* 3. Memory decoders:
* 2-4 ports will be added, depending on the ports available in the SRAM
* Among these, two ports are mandatory: BL and WL
* The other two ports are optional: BLB and WLB
* Note that the constraints are correletated to the checking rules
* in check_circuit_library()
********************************************************************/
std::vector<std::string> generate_sram_port_names(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz sram_orgz_type) {
std::vector<std::string> sram_port_names;
/* Prepare a list of port types to be added, the port type will be used to create port names */
std::vector<e_spice_model_port_type> model_port_types;
switch (sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
model_port_types.push_back(SPICE_MODEL_PORT_INPUT);
model_port_types.push_back(SPICE_MODEL_PORT_OUTPUT);
break;
case SPICE_SRAM_SCAN_CHAIN:
model_port_types.push_back(SPICE_MODEL_PORT_INPUT);
model_port_types.push_back(SPICE_MODEL_PORT_OUTPUT);
break;
case SPICE_SRAM_MEMORY_BANK: {
std::vector<e_spice_model_port_type> ports_to_search;
ports_to_search.push_back(SPICE_MODEL_PORT_BL);
ports_to_search.push_back(SPICE_MODEL_PORT_WL);
ports_to_search.push_back(SPICE_MODEL_PORT_BLB);
ports_to_search.push_back(SPICE_MODEL_PORT_WLB);
/* Try to find a BL/WL/BLB/WLB port and update the port types/module port types to be added */
for (const auto& port_to_search : ports_to_search) {
std::vector<CircuitPortId> found_port = circuit_lib.model_ports_by_type(sram_model, port_to_search);
if (0 == found_port.size()) {
continue;
}
model_port_types.push_back(port_to_search);
}
break;
}
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
__FILE__, __LINE__);
exit(1);
}
/* Add ports to the module manager */
for (size_t iport = 0; iport < model_port_types.size(); ++iport) {
/* Create a port */
std::string port_name = generate_sram_port_name(sram_orgz_type, model_port_types[iport]);
sram_port_names.push_back(port_name);
}
return sram_port_names;
}
/********************************************************************
* Generate a list of ports that are used for SRAM configuration to a module
* 1. Standalone SRAMs:
* use the suggested port_size
* 2. Scan-chain Flip-flops:
* IMPORTANT: the port size will be forced to 1 in this case
* 3. Memory decoders:
* use the suggested port_size
********************************************************************/
size_t generate_sram_port_size(const e_sram_orgz sram_orgz_type,
const size_t& num_config_bits) {
size_t sram_port_size = num_config_bits;
switch (sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
break;
case SPICE_SRAM_SCAN_CHAIN:
/* CCFF head/tail are single-bit ports */
sram_port_size = 1;
break;
case SPICE_SRAM_MEMORY_BANK:
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
__FILE__, __LINE__);
exit(1);
}
return sram_port_size;
}

View File

@ -24,4 +24,11 @@ bool check_mem_config_bus(const e_sram_orgz& sram_orgz_type,
const BasicPort& config_bus,
const size_t& local_expected_msb);
std::vector<std::string> generate_sram_port_names(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz sram_orgz_type);
size_t generate_sram_port_size(const e_sram_orgz sram_orgz_type,
const size_t& num_config_bits);
#endif

View File

@ -442,9 +442,9 @@ void ModuleManager::add_child_module(const ModuleId& parent_module, const Module
/* Update fast look-up for nets */
size_t instance_id = net_lookup_[parent_module][child_module].size();
net_lookup_[parent_module][child_module].emplace_back();
/* Find the ports for the child module and update the fast look-up */
for (ModulePortId child_port : port_ids_[child_module]) {
net_lookup_[parent_module][child_module].emplace_back();
net_lookup_[parent_module][child_module][instance_id][child_port].resize(ports_[child_module][child_port].get_width(), ModuleNetId::INVALID());
}
}

View File

@ -133,6 +133,7 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
module_manager.set_port_preproc_flag(module_id, port_id, preproc_flag);
}
/********************************************************************
* Add a list of ports that are used for SRAM configuration to a module
* in the module manager
@ -157,60 +158,15 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz sram_orgz_type,
const size_t& port_size) {
/* Prepare a list of port types to be added, the port type will be used to create port names */
std::vector<e_spice_model_port_type> model_port_types;
/* Prepare a list of module port types to be added, the port type will be used to specify the port type in Verilog/SPICE module */
std::vector<ModuleManager::e_module_port_type> module_port_types;
/* Actual port size may be different from user specification. Think about CCFF */
size_t sram_port_size = port_size;
switch (sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
model_port_types.push_back(SPICE_MODEL_PORT_INPUT);
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
model_port_types.push_back(SPICE_MODEL_PORT_OUTPUT);
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
break;
case SPICE_SRAM_SCAN_CHAIN:
model_port_types.push_back(SPICE_MODEL_PORT_INPUT);
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
model_port_types.push_back(SPICE_MODEL_PORT_OUTPUT);
module_port_types.push_back(ModuleManager::MODULE_OUTPUT_PORT);
/* CCFF head/tail are single-bit ports */
sram_port_size = 1;
break;
case SPICE_SRAM_MEMORY_BANK: {
std::vector<e_spice_model_port_type> ports_to_search;
ports_to_search.push_back(SPICE_MODEL_PORT_BL);
ports_to_search.push_back(SPICE_MODEL_PORT_WL);
ports_to_search.push_back(SPICE_MODEL_PORT_BLB);
ports_to_search.push_back(SPICE_MODEL_PORT_WLB);
/* Try to find a BL/WL/BLB/WLB port and update the port types/module port types to be added */
for (const auto& port_to_search : ports_to_search) {
std::vector<CircuitPortId> found_port = circuit_lib.model_ports_by_type(sram_model, port_to_search);
if (0 == found_port.size()) {
continue;
}
model_port_types.push_back(port_to_search);
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
}
break;
}
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
__FILE__, __LINE__);
exit(1);
}
const size_t& num_config_bits) {
std::vector<std::string> sram_port_names = generate_sram_port_names(circuit_lib, sram_model, sram_orgz_type);
size_t sram_port_size = generate_sram_port_size(sram_orgz_type, num_config_bits);
/* Add ports to the module manager */
for (size_t iport = 0; iport < model_port_types.size(); ++iport) {
/* Create a port */
std::string port_name = generate_sram_port_name(sram_orgz_type, model_port_types[iport]);
BasicPort module_port(port_name, sram_port_size);
for (const std::string& sram_port_name : sram_port_names) {
/* Add generated ports to the ModuleManager */
module_manager.add_port(module_id, module_port, module_port_types[iport]);
BasicPort sram_port(sram_port_name, sram_port_size);
module_manager.add_port(module_id, sram_port, ModuleManager::MODULE_INPUT_PORT);
}
}
@ -222,9 +178,9 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager,
* This function will also check that each pb_type port is actually exist
* in the linked circuit model
*******************************************************************/
void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
t_pb_type* cur_pb_type) {
void add_primitive_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
t_pb_type* cur_pb_type) {
/* Find the inout ports required by the primitive pb_type, and add them to the module */
std::vector<t_port*> pb_type_inout_ports = find_pb_type_ports_match_circuit_model_port_type(cur_pb_type, SPICE_MODEL_PORT_INOUT);
@ -263,6 +219,32 @@ void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
}
}
/********************************************************************
* Add ports of a pb_type block to module manager
* This function is designed for non-primitive pb_types, which are
* NOT linked to any circuit model.
* Actually, this makes things much simpler.
* We just iterate over all the ports and add it to the module
* with the naming convention
*******************************************************************/
void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
t_pb_type* cur_pb_type) {
/* Create a type-to-type mapping between module ports and pb_type ports */
std::map<PORTS, ModuleManager::e_module_port_type> port_type2type_map;
port_type2type_map[IN_PORT] = ModuleManager::MODULE_INPUT_PORT;
port_type2type_map[OUT_PORT] = ModuleManager::MODULE_OUTPUT_PORT;
port_type2type_map[INOUT_PORT] = ModuleManager::MODULE_INOUT_PORT;
for (int port = 0; port < cur_pb_type->num_ports; ++port) {
t_port* pb_type_port = &(cur_pb_type->ports[port]);
BasicPort module_port(generate_pb_type_port_name(pb_type_port), pb_type_port->num_pins);
module_manager.add_port(module_id, module_port, port_type2type_map[pb_type_port->type]);
/* Set the port to be wire-connection */
module_manager.set_port_is_wire(module_id, module_port.get_name(), true);
}
}
/********************************************************************
* Identify if a net is a local wire inside a module:
* A net is a local wire if it connects between two instances,
@ -832,6 +814,33 @@ void add_module_nets_memory_config_bus(ModuleManager& module_manager,
}
}
/********************************************************************
* Find the size of configuration ports for module
*******************************************************************/
size_t find_module_num_config_bits(const ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz& sram_orgz_type) {
std::vector<std::string> config_port_names = generate_sram_port_names(circuit_lib, sram_model, sram_orgz_type);
size_t num_config_bits = 0; /* By default it has zero configuration bits*/
/* Try to find these ports in the module manager */
for (const std::string& config_port_name : config_port_names) {
ModulePortId module_port_id = module_manager.find_module_port(module_id, config_port_name);
/* If the port does not exist, go to the next */
if (false == module_manager.valid_module_port_id(module_id, module_port_id)) {
continue;
}
/* The port exist, find the port size and update the num_config_bits if the size is larger */
BasicPort module_port = module_manager.module_port(module_id, module_port_id);
num_config_bits = std::max((int)num_config_bits, (int)module_port.get_width());
}
return num_config_bits;
}
/********************************************************************
* TODO:
* Add the port-to-port connection between a logic module

View File

@ -37,7 +37,11 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz sram_orgz_type,
const size_t& port_size);
const size_t& num_config_bits);
void add_primitive_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
t_pb_type* cur_pb_type);
void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
const ModuleId& module_id,
@ -72,4 +76,10 @@ void add_module_nets_memory_config_bus(ModuleManager& module_manager,
const e_sram_orgz& sram_orgz_type,
const e_spice_model_design_tech& mem_tech);
size_t find_module_num_config_bits(const ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz& sram_orgz_type);
#endif

View File

@ -115,7 +115,7 @@ void print_verilog_primitive_block(std::fstream& fp,
* Since we have linked pb_type ports to circuit models when setting up FPGA-X2P,
* no ports of the circuit model will be missing here
*/
add_pb_type_ports_to_module_manager(module_manager, primitive_module, primitive_pb_graph_node->pb_type);
add_primitive_pb_type_ports_to_module_manager(module_manager, primitive_module, primitive_pb_graph_node->pb_type);
/* Add configuration ports */
/* Shared SRAM ports*/
@ -273,43 +273,83 @@ void print_verilog_physical_blocks_rec(std::fstream& fp,
ModuleId pb_module = module_manager.add_module(pb_module_name);
VTR_ASSERT(ModuleId::INVALID() != pb_module);
/* TODO: Add ports to the Verilog module */
/* Add ports to the Verilog module */
add_pb_type_ports_to_module_manager(module_manager, pb_module, physical_pb_type);
/* TODO: Count I/O (INOUT) ports from the sub-modules under this Verilog module */
/* TODO: Count shared SRAM ports from the sub-modules under this Verilog module */
/* TODO: Count SRAM ports from the sub-modules under this Verilog module */
/* TODO: Count formal verification ports from the sub-modules under this Verilog module */
/* Print Verilog module declaration */
print_verilog_module_declaration(fp, module_manager, pb_module);
/* Comment lines */
print_verilog_comment(fp, std::string("----- BEGIN Physical programmable logic block Verilog module: " + std::string(physical_pb_type->name) + " -----"));
/* TODO: Print local wires (bus wires for memory configuration) */
/*
dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info,
stamped_sram_cnt,
stamped_sram_cnt + num_conf_bits - 1);
/* Vectors to record all the memory modules have been added
* They are used to add module nets of configuration bus
*/
std::vector<ModuleId> memory_modules;
std::vector<size_t> memory_instances;
/* TODO: this should be added to the cur_sram_orgz_info !!! */
t_spice_model* mem_model = NULL;
get_sram_orgz_info_mem_model(cur_sram_orgz_info, & mem_model);
CircuitModelId sram_model = circuit_lib.model(mem_model->name);
VTR_ASSERT(CircuitModelId::INVALID() != sram_model);
/* TODO: Add all the child Verilog modules as instances */
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
/* Get the name and module id for this child pb_type */
std::string child_pb_module_name = generate_physical_block_module_name(pb_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]));
ModuleId child_pb_module = module_manager.find_module(child_pb_module_name);
/* We must have one valid id! */
VTR_ASSERT(true == module_manager.valid_module_id(child_pb_module));
/* TODO: Instanciate all the child Verilog modules */
for (int ipb = 0; ipb < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ipb++) {
/* Each child may exist multiple times in the hierarchy*/
for (int jpb = 0; jpb < physical_pb_type->modes[physical_mode_index].pb_type_children[ipb].num_pb; jpb++) {
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
/* we should make sure this placement index == child_pb_type[jpb] */
VTR_ASSERT(jpb == physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ipb][jpb].placement_index);
VTR_ASSERT(inst == physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst].placement_index);
size_t child_instance_id = module_manager.num_instance(pb_module, child_pb_module);
/* Add the memory module as a child of primitive module */
module_manager.add_child_module(pb_module, child_pb_module);
/* TODO: Identify if this sub module includes configuration bits,
* we will update the memory module and instance list
*/
if (0 < find_module_num_config_bits(module_manager, child_pb_module,
circuit_lib, sram_model,
cur_sram_orgz_info->type)) {
memory_modules.push_back(child_pb_module);
memory_instances.push_back(child_instance_id);
}
}
}
/* TODO: Print programmable/non-programmable interconnections inside the Verilog module */
/* TODO: 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
*/
/* TODO: Count I/O (INOUT) 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
*/
/* TODO: Count shared SRAM 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
*/
/* TODO: Count SRAM 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
*/
/* TODO: Add modules and nets for programmable/non-programmable interconnections
* inside the Verilog module */
/*
dump_verilog_pb_graph_interc(cur_sram_orgz_info, fp, subckt_name,
cur_pb_graph_node, mode_index,
is_explicit_mapping);
*/
/* Print an end to the Verilog module */
print_verilog_module_end(fp, module_manager.module_name(pb_module));
/* Comment lines */
print_verilog_comment(fp, std::string("----- BEGIN Physical programmable logic block Verilog module: " + std::string(physical_pb_type->name) + " -----"));
/* Write the verilog module */
write_verilog_module_to_file(fp, module_manager, pb_module, use_explicit_mapping);
print_verilog_comment(fp, std::string("----- END Physical programmable logic block Verilog module: " + std::string(physical_pb_type->name) + " -----"));