/******************************************************************** * This file includes the functions of builders for MuxLibrary. *******************************************************************/ #include #include #include "vtr_assert.h" /* Device-level header files */ #include "util.h" #include "vpr_types.h" #include "globals.h" /* FPGA-X2P context header files */ #include "fpga_x2p_utils.h" #include "spice_types.h" #include "circuit_library.h" #include "mux_library.h" #include "mux_library_builder.h" /******************************************************************** * Update MuxLibrary with the unique multiplexer structures * found in the global routing architecture *******************************************************************/ static void build_routing_arch_mux_library(MuxLibrary& mux_lib, int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_switch_inf* switches, const CircuitLibrary& circuit_lib, t_det_routing_arch* routing_arch) { /* Current Version: Support Uni-directional routing architecture only*/ if (UNI_DIRECTIONAL != routing_arch->directionality) { vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d]) FPGA X2P Only supports uni-directional routing architecture.\n", __FILE__, __LINE__); exit(1); } /* The routing path is. * OPIN ----> CHAN ----> ... ----> CHAN ----> IPIN * Each edge is a switch, for IPIN, the switch is a connection block, * for the rest is a switch box */ /* Count the sizes of muliplexers in routing architecture */ for (int inode = 0; inode < LL_num_rr_nodes; inode++) { t_rr_node& node = LL_rr_node[inode]; switch (node.type) { case IPIN: { /* Have to consider the fan_in only, it is a connection block (multiplexer)*/ VTR_ASSERT((node.fan_in > 0) || (0 == node.fan_in)); if ( (0 == node.fan_in) || (1 == node.fan_in)) { break; } /* Find the circuit_model for multiplexers in connection blocks */ const CircuitModelId& cb_switch_circuit_model = switches[node.driver_switch].circuit_model; /* we should select a circuit model for the connection box*/ VTR_ASSERT(CircuitModelId::INVALID() != cb_switch_circuit_model); /* Add the mux to mux_library */ mux_lib.add_mux(circuit_lib, cb_switch_circuit_model, node.fan_in); break; } case CHANX: case CHANY: { /* Channels are the same, have to consider the fan_in as well, * it could be a switch box if previous rr_node is a channel * or it could be a connection box if previous rr_node is a IPIN or OPIN */ VTR_ASSERT((node.fan_in > 0) || (0 == node.fan_in)); if ((0 == node.fan_in) || (1 == node.fan_in)) { break; } /* Find the spice_model for multiplexers in switch blocks*/ const CircuitModelId& sb_switch_circuit_model = switches[node.driver_switch].circuit_model; /* we should select a circuit model for the Switch box*/ VTR_ASSERT(CircuitModelId::INVALID() != sb_switch_circuit_model); /* Add the mux to mux_library */ mux_lib.add_mux(circuit_lib, sb_switch_circuit_model, node.fan_in); break; } default: /* We do not care other types of rr_node */ break; } } } /******************************************************************** * Update MuxLibrary with the unique multiplexer structures * found in programmable logic blocks ********************************************************************/ static void build_pb_type_mux_library_rec(MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, t_pb_type* cur_pb_type) { VTR_ASSERT(nullptr != cur_pb_type); /* If there is spice_model_name, this is a leaf node!*/ if (TRUE == is_primitive_pb_type(cur_pb_type)) { /* What annoys me is VPR create a sub pb_type for each lut which suppose to be a leaf node * This may bring software convience but ruins circuit modeling */ VTR_ASSERT(CircuitModelId::INVALID() != cur_pb_type->phy_pb_type->circuit_model); return; } /* Traversal the hierarchy, find all the multiplexer from the interconnection part */ for (int imode = 0; imode < cur_pb_type->num_modes; imode++) { /* Then we have to statisitic the interconnections*/ for (int jinterc = 0; jinterc < cur_pb_type->modes[imode].num_interconnect; jinterc++) { /* Check the num_mux and fan_in of an interconnection */ VTR_ASSERT ((0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux) || (0 < cur_pb_type->modes[imode].interconnect[jinterc].num_mux)); if (0 == cur_pb_type->modes[imode].interconnect[jinterc].num_mux) { continue; } CircuitModelId& interc_circuit_model = cur_pb_type->modes[imode].interconnect[jinterc].circuit_model; VTR_ASSERT(CircuitModelId::INVALID() != interc_circuit_model); /* Add the mux model to library */ mux_lib.add_mux(circuit_lib, interc_circuit_model, cur_pb_type->modes[imode].interconnect[jinterc].fan_in); } } /* Go recursively to the lower level */ for (int imode = 0; imode < cur_pb_type->num_modes; imode++) { for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ichild++) { build_pb_type_mux_library_rec(mux_lib, circuit_lib, &cur_pb_type->modes[imode].pb_type_children[ichild]); } } } /******************************************************************** * Update MuxLibrary with the unique multiplexers required by * LUTs in the circuit library ********************************************************************/ static void build_lut_mux_library(MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib) { /* Find all the circuit models which are LUTs in the circuit library */ for (const auto& circuit_model : circuit_lib.models()) { /* Bypass non-LUT circuit models */ if (SPICE_MODEL_LUT != circuit_lib.model_type(circuit_model)) { continue; } /* Find the MUX size required by the LUT */ /* Get input ports which are not global ports! */ std::vector input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true); VTR_ASSERT(1 == input_ports.size()); /* MUX size = 2^lut_size */ size_t lut_mux_size = (size_t)pow(2., (double)(circuit_lib.port_size(input_ports[0]))); /* Add mux to the mux library */ mux_lib.add_mux(circuit_lib, circuit_model, lut_mux_size); } } /* Statistic for all the multiplexers in FPGA * We determine the sizes and its structure (according to spice_model) for each type of multiplexers * We search multiplexers in Switch Blocks, Connection blocks and Configurable Logic Blocks * In additional to multiplexers, this function also consider crossbars. * All the statistics are stored in a linked list, as a return value */ MuxLibrary build_device_mux_library(int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_switch_inf* switches, const CircuitLibrary& circuit_lib, t_det_routing_arch* routing_arch) { /* MuxLibrary to store the information of Multiplexers*/ MuxLibrary mux_lib; /* Step 1: We should check the multiplexer spice models defined in routing architecture.*/ build_routing_arch_mux_library(mux_lib, LL_num_rr_nodes, LL_rr_node, switches, circuit_lib, routing_arch); /* Step 2: Count the sizes of multiplexers in complex logic blocks */ for (int itype = 0; itype < num_types; itype++) { if (NULL != type_descriptors[itype].pb_type) { build_pb_type_mux_library_rec(mux_lib, circuit_lib, type_descriptors[itype].pb_type); } } /* Step 3: count the size of multiplexer that will be used in LUTs*/ build_lut_mux_library(mux_lib, circuit_lib); return mux_lib; }