openfpga/src/fabric/build_mux_modules.cpp
/*********************************************************************
 * Generate module of a CMOS multiplexer with the given size 
 * The module will consist of three parts:
 * 1. instances of the branch circuits of multiplexers which are generated before  
 *    This builds up the multiplexing structure
 * 2. Input buffers/inverters
 * 3. Output buffers/inverters
 *********************************************************************/
Generate module of a CMOS multiplexer with the given size
The module will consist of three parts:
1. instances of the branch circuits of multiplexers which are generated before
This builds up the multiplexing structure
2. Input buffers/inverters
3. Output buffers/inverters
Generate module of a CMOS multiplexer with the given size The module will consist of three parts : 1 . instances of the branch circuits of multiplexers which are generated before This builds up the multiplexing structure 2 . Input buffers / inverters 3 . Output buffers / inverters
static 
void build_cmos_mux_module(ModuleManager& module_manager,
                           const CircuitLibrary& circuit_lib, 
                           const CircuitModelId& mux_model, 
                           const std::string& module_name, 
                           const MuxGraph& mux_graph) {
  std::vector<CircuitPortId> mux_global_ports = circuit_lib.model_global_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
  std::vector<CircuitPortId> mux_input_ports;
  if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
     mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, mux_model, false, false);
  } else {
     VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
     mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
  }
  std::vector<CircuitPortId> mux_output_ports;
  if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
     mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, mux_model, false, true);
  } else {
     VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
     mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
  }
  std::vector<CircuitPortId> mux_sram_ports = find_circuit_regular_sram_ports(circuit_lib, mux_model);
  size_t num_inputs = find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs());
  size_t num_outputs = mux_graph.num_outputs();
  size_t num_mems = mux_graph.num_memory_bits();
  if (true == circuit_lib.mux_use_local_encoder(mux_model)) {
    num_mems = 0;
    for (const auto& lvl : mux_graph.levels()) {
      size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
      num_mems += find_mux_local_decoder_addr_size(data_size);
    } 
  }
  VTR_ASSERT(1 == mux_input_ports.size());
  if ((CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model))
    || ((CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model))
       && (false == circuit_lib.is_lut_fracturable(mux_model))) ) {
    VTR_ASSERT(1 == mux_output_ports.size());
    VTR_ASSERT(1 == circuit_lib.port_size(mux_output_ports[0])); 
  } else {
    VTR_ASSERT_SAFE( (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) 
                 && (true == circuit_lib.is_lut_fracturable(mux_model)) );
    for (const auto& port : mux_output_ports) {
      VTR_ASSERT(0 < circuit_lib.port_size(port));
    }
  }
  ModuleId mux_module = module_manager.add_module(module_name); 
  VTR_ASSERT(ModuleId::INVALID() != mux_module);
  if (CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model)) {
    module_manager.set_module_usage(mux_module, ModuleManager::MODULE_INTERC);
  } else {
    VTR_ASSERT_SAFE(CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)); 
    module_manager.set_module_usage(mux_module, ModuleManager::MODULE_LUT);
  }
  size_t input_port_cnt = 0;
  for (const auto& port : mux_input_ports) {
    BasicPort input_port(circuit_lib.port_prefix(port), num_inputs);
    module_manager.add_port(mux_module, input_port, ModuleManager::MODULE_INPUT_PORT);
    input_port_cnt++;
  }
  VTR_ASSERT(1 == input_port_cnt);
  vtr::vector<MuxInputId, ModuleNetId> mux_input_nets = build_mux_module_input_buffers(module_manager, circuit_lib, mux_module, mux_model, mux_graph);
  for (const auto& port : mux_output_ports) {
    BasicPort output_port(circuit_lib.port_prefix(port), num_outputs);
    if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
      output_port.set_width(circuit_lib.port_size(port));
    }
    module_manager.add_port(mux_module, output_port, ModuleManager::MODULE_OUTPUT_PORT);
  }
  vtr::vector<MuxOutputId, ModuleNetId> mux_output_nets = build_mux_module_output_buffers(module_manager, circuit_lib, mux_module, mux_model, mux_graph);
  size_t sram_port_cnt = 0;
  for (const auto& port : mux_sram_ports) {
    BasicPort mem_port(circuit_lib.port_prefix(port), num_mems);
    module_manager.add_port(mux_module, mem_port, ModuleManager::MODULE_INPUT_PORT);
    BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + INV_PORT_POSTFIX), num_mems);
    module_manager.add_port(mux_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
    sram_port_cnt++;
  }
  VTR_ASSERT(1 == sram_port_cnt);
  vtr::vector<MuxMemId, ModuleNetId> mux_mem_nets;
  vtr::vector<MuxMemId, ModuleNetId> mux_mem_inv_nets;
  build_mux_module_local_encoders_and_memory_nets(module_manager, mux_module, 
                                                  circuit_lib, mux_model, mux_sram_ports, 
                                                  mux_graph,
                                                  mux_mem_nets, mux_mem_inv_nets);
  CircuitModelId tgate_model = circuit_lib.pass_gate_logic_model(mux_model);
  std::string branch_module_name;
  if (CIRCUIT_MODEL_GATE == circuit_lib.model_type(tgate_model)) {
    VTR_ASSERT(CIRCUIT_MODEL_GATE_MUX2 == circuit_lib.gate_type(tgate_model));
    build_cmos_mux_module_mux2_multiplexing_structure(module_manager, circuit_lib, mux_module, mux_model, tgate_model, mux_input_nets, mux_output_nets, mux_mem_nets, mux_graph);
  } else {
    VTR_ASSERT(CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(tgate_model));
    build_cmos_mux_module_tgate_multiplexing_structure(module_manager, circuit_lib, mux_module, mux_model, mux_input_nets, mux_output_nets, mux_mem_nets, mux_mem_inv_nets, mux_graph);
  }
  add_module_global_ports_from_child_modules(module_manager, mux_module);
}
static void build_cmos_mux_module ( ModuleManager & module_manager , const CircuitLibrary & circuit_lib , const CircuitModelId & mux_model , const std :: string & module_name , const MuxGraph & mux_graph ) { std :: vector < CircuitPortId > mux_global_ports = circuit_lib . model_global_ports_by_type ( mux_model , CIRCUIT_MODEL_PORT_INPUT , true , true ) ; std :: vector < CircuitPortId > mux_input_ports ; if ( CIRCUIT_MODEL_LUT == circuit_lib . model_type ( mux_model ) ) { mux_input_ports = find_lut_circuit_model_input_port ( circuit_lib , mux_model , false , false ) ; } else { VTR_ASSERT ( CIRCUIT_MODEL_MUX == circuit_lib . model_type ( mux_model ) ) ; mux_input_ports = circuit_lib . model_ports_by_type ( mux_model , CIRCUIT_MODEL_PORT_INPUT , true ) ; } std :: vector < CircuitPortId > mux_output_ports ; if ( CIRCUIT_MODEL_LUT == circuit_lib . model_type ( mux_model ) ) { mux_output_ports = find_lut_circuit_model_output_port ( circuit_lib , mux_model , false , true ) ; } else { VTR_ASSERT ( CIRCUIT_MODEL_MUX == circuit_lib . model_type ( mux_model ) ) ; mux_output_ports = circuit_lib . model_ports_by_type ( mux_model , CIRCUIT_MODEL_PORT_OUTPUT , false ) ; } std :: vector < CircuitPortId > mux_sram_ports = find_circuit_regular_sram_ports ( circuit_lib , mux_model ) ; size_t num_inputs = find_mux_num_datapath_inputs ( circuit_lib , mux_model , mux_graph . num_inputs ( ) ) ; size_t num_outputs = mux_graph . num_outputs ( ) ; size_t num_mems = mux_graph . num_memory_bits ( ) ; if ( true == circuit_lib . mux_use_local_encoder ( mux_model ) ) { num_mems = 0 ; for ( const auto & lvl : mux_graph . levels ( ) ) { size_t data_size = mux_graph . num_memory_bits_at_level ( lvl ) ; num_mems += find_mux_local_decoder_addr_size ( data_size ) ; } } VTR_ASSERT ( 1 == mux_input_ports . size ( ) ) ; if ( ( CIRCUIT_MODEL_MUX == circuit_lib . model_type ( mux_model ) ) || ( ( CIRCUIT_MODEL_LUT == circuit_lib . model_type ( mux_model ) ) && ( false == circuit_lib . is_lut_fracturable ( mux_model ) ) ) ) { VTR_ASSERT ( 1 == mux_output_ports . size ( ) ) ; VTR_ASSERT ( 1 == circuit_lib . port_size ( mux_output_ports [ 0 ] ) ) ; } else { VTR_ASSERT_SAFE ( ( CIRCUIT_MODEL_LUT == circuit_lib . model_type ( mux_model ) ) && ( true == circuit_lib . is_lut_fracturable ( mux_model ) ) ) ; for ( const auto & port : mux_output_ports ) { VTR_ASSERT ( 0 < circuit_lib . port_size ( port ) ) ; } } ModuleId mux_module = module_manager . add_module ( module_name ) ; VTR_ASSERT ( ModuleId :: INVALID ( ) != mux_module ) ; if ( CIRCUIT_MODEL_MUX == circuit_lib . model_type ( mux_model ) ) { module_manager . set_module_usage ( mux_module , ModuleManager :: MODULE_INTERC ) ; } else { VTR_ASSERT_SAFE ( CIRCUIT_MODEL_LUT == circuit_lib . model_type ( mux_model ) ) ; module_manager . set_module_usage ( mux_module , ModuleManager :: MODULE_LUT ) ; } size_t input_port_cnt = 0 ; for ( const auto & port : mux_input_ports ) { BasicPort input_port ( circuit_lib . port_prefix ( port ) , num_inputs ) ; module_manager . add_port ( mux_module , input_port , ModuleManager :: MODULE_INPUT_PORT ) ; input_port_cnt ++ ; } VTR_ASSERT ( 1 == input_port_cnt ) ; vtr :: vector < MuxInputId , ModuleNetId > mux_input_nets = build_mux_module_input_buffers ( module_manager , circuit_lib , mux_module , mux_model , mux_graph ) ; for ( const auto & port : mux_output_ports ) { BasicPort output_port ( circuit_lib . port_prefix ( port ) , num_outputs ) ; if ( CIRCUIT_MODEL_LUT == circuit_lib . model_type ( mux_model ) ) { output_port . set_width ( circuit_lib . port_size ( port ) ) ; } module_manager . add_port ( mux_module , output_port , ModuleManager :: MODULE_OUTPUT_PORT ) ; } vtr :: vector < MuxOutputId , ModuleNetId > mux_output_nets = build_mux_module_output_buffers ( module_manager , circuit_lib , mux_module , mux_model , mux_graph ) ; size_t sram_port_cnt = 0 ; for ( const auto & port : mux_sram_ports ) { BasicPort mem_port ( circuit_lib . port_prefix ( port ) , num_mems ) ; module_manager . add_port ( mux_module , mem_port , ModuleManager :: MODULE_INPUT_PORT ) ; BasicPort mem_inv_port ( std :: string ( circuit_lib . port_prefix ( port ) + INV_PORT_POSTFIX ) , num_mems ) ; module_manager . add_port ( mux_module , mem_inv_port , ModuleManager :: MODULE_INPUT_PORT ) ; sram_port_cnt ++ ; } VTR_ASSERT ( 1 == sram_port_cnt ) ; vtr :: vector < MuxMemId , ModuleNetId > mux_mem_nets ; vtr :: vector < MuxMemId , ModuleNetId > mux_mem_inv_nets ; build_mux_module_local_encoders_and_memory_nets ( module_manager , mux_module , circuit_lib , mux_model , mux_sram_ports , mux_graph , mux_mem_nets , mux_mem_inv_nets ) ; CircuitModelId tgate_model = circuit_lib . pass_gate_logic_model ( mux_model ) ; std :: string branch_module_name ; if ( CIRCUIT_MODEL_GATE == circuit_lib . model_type ( tgate_model ) ) { VTR_ASSERT ( CIRCUIT_MODEL_GATE_MUX2 == circuit_lib . gate_type ( tgate_model ) ) ; build_cmos_mux_module_mux2_multiplexing_structure ( module_manager , circuit_lib , mux_module , mux_model , tgate_model , mux_input_nets , mux_output_nets , mux_mem_nets , mux_graph ) ; } else { VTR_ASSERT ( CIRCUIT_MODEL_PASSGATE == circuit_lib . model_type ( tgate_model ) ) ; build_cmos_mux_module_tgate_multiplexing_structure ( module_manager , circuit_lib , mux_module , mux_model , mux_input_nets , mux_output_nets , mux_mem_nets , mux_mem_inv_nets , mux_graph ) ; } add_module_global_ports_from_child_modules ( module_manager , mux_module ) ; }
Generate module of a CMOS multiplexer with the given size
 The module will consist of three parts:
 1. instances of the branch circuits of multiplexers which are generated before
    This builds up the multiplexing structure
 2.
Generate module of a CMOS multiplexer with the given size The module will consist of three parts : 1 . instances of the branch circuits of multiplexers which are generated before This builds up the multiplexing structure 2 .
/* Get the global ports required by MUX (and any submodules) */ /* Get the input ports from the mux:
   * - LUT may have ports that are driven by harden logic, 
   *   which should not be included when building the mux graph
   */ /* Get the output ports from the mux:
   * - LUT may have ports that are driven by harden logic, 
   *   which should not be included when building the mux graph
   * - LUT may have global output ports that are wired directly to top-level module 
   */ /* Get the sram ports from the mux 
   * Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
   * Here we just bypass it.
   */ /* Generate the Verilog netlist according to the mux_graph */ /* Find out the number of data-path inputs */ /* Find out the number of outputs */ /* Find out the number of memory bits */ /* The size of of memory ports depend on 
   * if a local encoder is used for the mux or not 
   * Multiplexer local encoders are applied to memory bits at each stage 
   */ /* Check codes to ensure the port of Verilog netlists will match */ /* MUX graph must have only 1 output */ /* A quick check on the model ports */ /* Create a Verilog Module based on the circuit model, and add to module manager */ /* Label module usage */ /* Add module ports */ /* Add each input port
   * Treat MUX and LUT differently 
   * 1. MUXes: we do not have a specific input/output sizes, it is inferred by architecture 
   * 2. LUTes: we do have specific input/output sizes, 
   *           but the inputs of MUXes are the SRAM ports of LUTs
   *           and the SRAM ports of MUXes are the inputs of LUTs
   */ /* Update counter */ /* Double check: We should have only 1 input port generated here! */ /* Add input buffers and update module nets for inputs */ /* TODO: Add output buffers and update module nets for outputs */ /* Update counter */ /* Create module nets for mem and mem_inv ports */ /* Print the internal logic in Verilog codes */ /* Print the Multiplexing structure in Verilog codes 
   * Separated generation strategy on using standard cell MUX2 or TGATE,
   * 1. MUX2 has a fixed port map: input_port[0] and input_port[1] is the data_path input 
   * 2. Branch TGATE-based module has a fixed port name  
   * TODO: the naming could be more flexible? 
   */ /* Get the tgate model */ /* Instanciate the branch module: 
   * Case 1: the branch module is a standard cell MUX2
   * Case 2: the branch module is a tgate-based 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
   */