openfpga/src/fpga_spice/spice_buffer.cpp
/********************************************************************
 * Generate the SPICE subckt for a regular buffer
 * which contains at least 2 stages
 *
 * Note: 
 * - This function does NOT support power-gating
 *   It should be managed in a separated function
 *
 * Schematic of a multi-stage buffer
 * 
 *          LVDD              LVDD
 *            |                |
 *           -                -
 *      +-o||            +-o||
 *      |    -           |    -
 *      |     |          |     |
 * in-->+     +-- ... ---+---->+---> out
 *      |     |          |     |
 *      |    -           |    -
 *      +--||            +--||
 *           -                -
 *            |                |
 *          LGND             LGND
 *
 *******************************************************************/
Generate the SPICE subckt for a regular buffer
which contains at least 2 stages

- This function does NOT support power-gating
It should be managed in a separated function

Schematic of a multi-stage buffer


Generate the SPICE subckt for a regular buffer which contains at least 2 stages - This function does NOT support power - gating It should be managed in a separated function Schematic of a multi - stage buffer
static 
int print_spice_regular_buffer_subckt(std::fstream& fp,
                                      const ModuleManager& module_manager,
                                      const ModuleId& module_id,
                                      const CircuitLibrary& circuit_lib,
                                      const CircuitModelId& circuit_model,
                                      const TechnologyLibrary& tech_lib,
                                      const TechnologyModelId& tech_model) {
  if (false == valid_file_stream(fp)) {
    return CMD_EXEC_FATAL_ERROR;
  }
  print_spice_subckt_definition(fp, module_manager, module_id); 
  std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
  std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
  VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
  VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
  int status = CMD_EXEC_SUCCESS;
  VTR_ASSERT(2 <= circuit_lib.buffer_num_levels(circuit_model));
  std::vector<float> buffer_widths(circuit_lib.buffer_num_levels(circuit_model), 1);
  for (size_t level = 0; level < circuit_lib.buffer_num_levels(circuit_model); ++level) {
    buffer_widths[level] = circuit_lib.buffer_size(circuit_model)
                         * std::pow(circuit_lib.buffer_f_per_stage(circuit_model), level);
  }
  for (size_t level = 0; level < circuit_lib.buffer_num_levels(circuit_model); ++level) {
    std::string input_port_name = circuit_lib.port_prefix(input_ports[0]); 
    std::string output_port_name = circuit_lib.port_prefix(output_ports[0]); 
    if (0 == level) {
      output_port_name += std::string("_level") + std::to_string(level);
    } else {
      VTR_ASSERT(0 < level);
      input_port_name += std::string("_level") + std::to_string(level - 1);
    }
    float regular_pmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
    float total_pmos_width = buffer_widths[level]
                             * tech_lib.model_pn_ratio(tech_model)
                             * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
    int num_pmos_bins = std::ceil(total_pmos_width / regular_pmos_bin_width);
    float last_pmos_bin_width = std::fmod(total_pmos_width, regular_pmos_bin_width);
    for (int ibin = 0; ibin < num_pmos_bins; ++ibin) { 
      float curr_bin_width = regular_pmos_bin_width;
      if ((ibin == num_pmos_bins - 1) 
         && (0. != last_pmos_bin_width)) {
        curr_bin_width = last_pmos_bin_width;
      }
      std::string name_postfix = std::string("level") + std::to_string(level) + std::string("_bin") + std::to_string(ibin);
      status = print_spice_regular_inverter_pmos_modeling(fp,
                                                          name_postfix,
                                                          circuit_lib.port_prefix(input_ports[0]), 
                                                          circuit_lib.port_prefix(output_ports[0]), 
                                                          tech_lib,
                                                          tech_model,
                                                          curr_bin_width);
      if (CMD_EXEC_FATAL_ERROR == status) {
        return status;
      }
    }
    float regular_nmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
    float total_nmos_width = buffer_widths[level]
                              * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
    int num_nmos_bins = std::ceil(total_nmos_width / regular_nmos_bin_width);
    float last_nmos_bin_width = std::fmod(total_nmos_width, regular_nmos_bin_width);
    for (int ibin = 0; ibin < num_nmos_bins; ++ibin) { 
      float curr_bin_width = regular_nmos_bin_width;
      if ((ibin == num_nmos_bins - 1) 
         && (0. != last_nmos_bin_width)) {
        curr_bin_width = last_nmos_bin_width;
      }
      std::string name_postfix = std::string("level") + std::to_string(level) + std::string("_bin") + std::to_string(ibin);
      status = print_spice_regular_inverter_nmos_modeling(fp,
                                                          name_postfix,
                                                          circuit_lib.port_prefix(input_ports[0]), 
                                                          circuit_lib.port_prefix(output_ports[0]), 
                                                          tech_lib,
                                                          tech_model,
                                                          curr_bin_width);
      if (CMD_EXEC_FATAL_ERROR == status) {
        return status;
      }
    }
  }
  print_spice_subckt_end(fp, module_manager.module_name(module_id)); 
  return status;
}
static int print_spice_regular_buffer_subckt ( std :: fstream & fp , const ModuleManager & module_manager , const ModuleId & module_id , const CircuitLibrary & circuit_lib , const CircuitModelId & circuit_model , const TechnologyLibrary & tech_lib , const TechnologyModelId & tech_model ) { if ( false == valid_file_stream ( fp ) ) { return CMD_EXEC_FATAL_ERROR ; } print_spice_subckt_definition ( fp , module_manager , module_id ) ; std :: vector < CircuitPortId > input_ports = circuit_lib . model_ports_by_type ( circuit_model , CIRCUIT_MODEL_PORT_INPUT , true ) ; std :: vector < CircuitPortId > output_ports = circuit_lib . model_ports_by_type ( circuit_model , CIRCUIT_MODEL_PORT_OUTPUT , true ) ; VTR_ASSERT ( ( 1 == input_ports . size ( ) ) && ( 1 == circuit_lib . port_size ( input_ports [ 0 ] ) ) ) ; VTR_ASSERT ( ( 1 == output_ports . size ( ) ) && ( 1 == circuit_lib . port_size ( output_ports [ 0 ] ) ) ) ; int status = CMD_EXEC_SUCCESS ; VTR_ASSERT ( 2 <= circuit_lib . buffer_num_levels ( circuit_model ) ) ; std :: vector < float > buffer_widths ( circuit_lib . buffer_num_levels ( circuit_model ) , 1 ) ; for ( size_t level = 0 ; level < circuit_lib . buffer_num_levels ( circuit_model ) ; ++ level ) { buffer_widths [ level ] = circuit_lib . buffer_size ( circuit_model ) * std :: pow ( circuit_lib . buffer_f_per_stage ( circuit_model ) , level ) ; } for ( size_t level = 0 ; level < circuit_lib . buffer_num_levels ( circuit_model ) ; ++ level ) { std :: string input_port_name = circuit_lib . port_prefix ( input_ports [ 0 ] ) ; std :: string output_port_name = circuit_lib . port_prefix ( output_ports [ 0 ] ) ; if ( 0 == level ) { output_port_name += std :: string ( " " ) + std :: to_string ( level ) ; } else { VTR_ASSERT ( 0 < level ) ; input_port_name += std :: string ( " " ) + std :: to_string ( level - 1 ) ; } float regular_pmos_bin_width = tech_lib . transistor_model_max_width ( tech_model , TECH_LIB_TRANSISTOR_PMOS ) ; float total_pmos_width = buffer_widths [ level ] * tech_lib . model_pn_ratio ( tech_model ) * tech_lib . transistor_model_min_width ( tech_model , TECH_LIB_TRANSISTOR_PMOS ) ; int num_pmos_bins = std :: ceil ( total_pmos_width / regular_pmos_bin_width ) ; float last_pmos_bin_width = std :: fmod ( total_pmos_width , regular_pmos_bin_width ) ; for ( int ibin = 0 ; ibin < num_pmos_bins ; ++ ibin ) { float curr_bin_width = regular_pmos_bin_width ; if ( ( ibin == num_pmos_bins - 1 ) && ( 0. != last_pmos_bin_width ) ) { curr_bin_width = last_pmos_bin_width ; } std :: string name_postfix = std :: string ( " " ) + std :: to_string ( level ) + std :: string ( " " ) + std :: to_string ( ibin ) ; status = print_spice_regular_inverter_pmos_modeling ( fp , name_postfix , circuit_lib . port_prefix ( input_ports [ 0 ] ) , circuit_lib . port_prefix ( output_ports [ 0 ] ) , tech_lib , tech_model , curr_bin_width ) ; if ( CMD_EXEC_FATAL_ERROR == status ) { return status ; } } float regular_nmos_bin_width = tech_lib . transistor_model_max_width ( tech_model , TECH_LIB_TRANSISTOR_NMOS ) ; float total_nmos_width = buffer_widths [ level ] * tech_lib . transistor_model_min_width ( tech_model , TECH_LIB_TRANSISTOR_NMOS ) ; int num_nmos_bins = std :: ceil ( total_nmos_width / regular_nmos_bin_width ) ; float last_nmos_bin_width = std :: fmod ( total_nmos_width , regular_nmos_bin_width ) ; for ( int ibin = 0 ; ibin < num_nmos_bins ; ++ ibin ) { float curr_bin_width = regular_nmos_bin_width ; if ( ( ibin == num_nmos_bins - 1 ) && ( 0. != last_nmos_bin_width ) ) { curr_bin_width = last_nmos_bin_width ; } std :: string name_postfix = std :: string ( " " ) + std :: to_string ( level ) + std :: string ( " " ) + std :: to_string ( ibin ) ; status = print_spice_regular_inverter_nmos_modeling ( fp , name_postfix , circuit_lib . port_prefix ( input_ports [ 0 ] ) , circuit_lib . port_prefix ( output_ports [ 0 ] ) , tech_lib , tech_model , curr_bin_width ) ; if ( CMD_EXEC_FATAL_ERROR == status ) { return status ; } } } print_spice_subckt_end ( fp , module_manager . module_name ( module_id ) ) ; return status ; }
Generate the SPICE subckt for a regular buffer
 which contains at least 2 stages
Generate the SPICE subckt for a regular buffer which contains at least 2 stages
/* Print the inverter subckt definition */ /* Find the input and output ports:
   * we do NOT support global ports here, 
   * it should be handled in another type of inverter subckt (power-gated)
   */ /* Make sure:
   * There is only 1 input port and 1 output port, 
   * each size of which is 1
   */ /* Buffers must have >= 2 stages */ /* Build the array denoting width of inverters per stage */ /* Special for first stage: output port should be an intermediate node 
     * Special for rest of stages: input port should be the output of previous stage
     */ /* Consider use size/bin to compact layout:
     * Try to size transistors to the max width for each bin
     * The last bin may not reach the max width 
     */ /* For last bin, we need an irregular width */ /* Consider use size/bin to compact layout:
     * Try to size transistors to the max width for each bin
     * The last bin may not reach the max width 
     */ /* For last bin, we need an irregular width */