text: /*
   * Permission is hereby granted, free of charge, to any person
   * obtaining a copy of this software and associated documentation
   * files (the "Software"), to deal in the Software without
   * restriction, including without limitation the rights to use,
   * copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following
   * conditions:
   *
   * The above copyright notice and this permission notice shall be
   * included in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   * OTHER DEALINGS IN THE SOFTWARE.
   */
  
  #include <stdlib.h>
  #include <assert.h>
  #include <stdio.h>
  #include <string.h>
  #include <math.h>
  
  #include "odin_types.h"
  #include "odin_util.h"
  #include "node_creation_library.h"
  #include "adders.h"
  #include "netlist_utils.h"
  #include "partial_map.h"
  #include "read_xml_arch_file.h"
  #include "odin_globals.h"
  
  #include "multipliers.h"
  #include "subtractions.h"
  
  #include "vtr_memory.h"
  
  #include "vtr_list.h"
  
  using vtr::t_linked_vptr;
  
  t_model* hard_adders = NULL;
  t_linked_vptr* add_list = NULL;
  t_linked_vptr* processed_adder_list = NULL;
  t_linked_vptr* chain_list = NULL;
  int total = 0;
  int* adder = NULL;
  int min_add = 0;
  int min_threshold_adder = 0;
  
  netlist_t* the_netlist;
  
  void record_add_distribution(nnode_t* node);
  void init_split_adder(nnode_t* node, nnode_t* ptr, int a, int sizea, int b, int sizeb, int cin, int cout, int index, int flag, netlist_t* netlist);
  
  /*---------------------------------------------------------------------------
   * (function: init_add_distribution)
   *  For adder, the output will only be the maxim input size + 1
   *-------------------------------------------------------------------------*/
  void init_add_distribution() {
      oassert(hard_adders != NULL);
  
      int len = hard_adders->inputs->size + hard_adders->inputs->next->size + 1;
      adder = (int*)vtr::calloc(len, sizeof(int));
  }
  
  /*---------------------------------------------------------------------------
   * (function: record_add_distribution)
   *-------------------------------------------------------------------------*/
  void record_add_distribution(nnode_t* node) {
      oassert(hard_adders != NULL);
      oassert(node != NULL);
      adder[hard_adders->inputs->size] += 1;
      return;
  }
  
  /*---------------------------------------------------------------------------
   * (function: report_add_distribution)
   *-------------------------------------------------------------------------*/
  
  /* These values are collected during the unused logic removal sweep */
  extern long adder_chain_count;
  extern long longest_adder_chain;
  extern long total_adders;
  
  extern double geomean_addsub_length;
  extern double sum_of_addsub_logs;
  
  void report_add_distribution() {
      if (hard_adders == NULL)
          return;
  
      printf("\nHard adder Distribution\n");
      printf("============================\n");
      printf("\n");
      printf("\nTotal # of chains = %ld\n", adder_chain_count);
  
      printf("\nHard adder chain Details\n");
      printf("============================\n");
  
      printf("\n");
      printf("\nThe Number of Hard Block adders in the Longest Chain: %ld\n", longest_adder_chain);
  
      printf("\n");
      printf("\nThe Total Number of Hard Block adders: %ld\n", total_adders);
  
      printf("\n");
      printf("\nGeometric mean adder/subtractor chain length: %.2f\n", geomean_addsub_length);
  
      vtr::free(adder);
  }
  
  /*---------------------------------------------------------------------------
   * (function: find_hard_adders)
   *-------------------------------------------------------------------------*/
  void find_hard_adders() {
      hard_adders = Arch.models;
      //Disable the size in configuration file.(The threshold for the extra bits).
      //min_add = configuration.min_hard_adder;
      min_threshold_adder = configuration.min_threshold_adder;
  
      while (hard_adders != NULL) {
          if (strcmp(hard_adders->name, "adder") == 0) {
              init_add_distribution();
              return;
          } else {
              hard_adders = hard_adders->next;
          }
      }
  
      return;
  }
  
  /*---------------------------------------------------------------------------
   * (function: declare_hard_adder)
   *-------------------------------------------------------------------------*/
  void declare_hard_adder(nnode_t* node) {
      t_adder* tmp;
      int width_a, width_b, width_sumout;
  
      /* See if this size instance of adder exists? */
      if (hard_adders == NULL)
          warning_message(NETLIST_ERROR, node->related_ast_node->line_number, node->related_ast_node->file_number, "%s\n", "Instantiating adder where adders do not exist");
  
      tmp = (t_adder*)hard_adders->instances;
      width_a = node->input_port_sizes[0];
      width_b = node->input_port_sizes[1];
      width_sumout = node->output_port_sizes[1];
  
      while (tmp != NULL) {
          if ((tmp->size_a == width_a) && (tmp->size_b == width_b) && (tmp->size_sumout == width_sumout))
              return;
          else
              tmp = tmp->next;
      }
  
      /* Does not exist - must create an instance */
      tmp = (t_adder*)vtr::malloc(sizeof(t_adder));
      tmp->next = (t_adder*)hard_adders->instances;
      hard_adders->instances = tmp;
      tmp->size_a = width_a;
      tmp->size_b = width_b;
      tmp->size_cin = 1;
      tmp->size_cout = 1;
      tmp->size_sumout = width_sumout;
      return;
  }
  
  /*---------------------------------------------------------------------------
   * (function: instantiate_hard_addier )
   *-------------------------------------------------------------------------*/
  void instantiate_hard_adder(nnode_t* node, short mark, netlist_t* /*netlist*/) {
      char* new_name;
      int len, sanity, i;
  
      declare_hard_adder(node);
  
      /* Need to give node proper name */
      len = strlen(node->name);
      len = len + 20; /* 20 chars should hold mul specs */
      new_name = (char*)vtr::malloc(len);
  
      /* wide input first :) identical branches! */
      // if (node->input_port_sizes[0] > node->input_port_sizes[1])
      // 	sanity = odin_sprintf(new_name, "%s", node->name);
      // else
      sanity = odin_sprintf(new_name, "%s", node->name);
  
      if (new_name)
          vtr::free(new_name);
  
      if (len <= sanity) /* buffer not large enough */
          oassert(false);
  
      /* Give names to the output pins */
      for (i = 0; i < node->num_output_pins; i++) {
          if (node->output_pins[i]->name == NULL) {
              len = strlen(node->name) + 20; /* 6 chars for pin idx */
              new_name = (char*)vtr::malloc(len);
              odin_sprintf(new_name, "%s[%d]", node->name, node->output_pins[i]->pin_node_idx);
              node->output_pins[i]->name = new_name;
          }
      }
  
      node->traverse_visited = mark;
      return;
  }
  
  /*----------------------------------------------------------------------------
   * function: add_the_blackbox_for_adds()
   *--------------------------------------------------------------------------*/
  void add_the_blackbox_for_adds(FILE* out) {
      int i;
      int count;
      int hard_add_inputs, hard_add_outputs;
      t_adder* adds;
      t_model_ports* ports;
      char buffer[MAX_BUF];
      char *pa, *pb, *psumout, *pcin, *pcout;
  
      /* Check to make sure this target architecture has hard adders */
      if (hard_adders == NULL)
          return;
  
      /* Get the names of the ports for the adder */
      ports = hard_adders->inputs;
      pcin = ports->name;
      ports = ports->next;
      pb = ports->name;
      ports = ports->next;
      pa = ports->name;
  
      ports = hard_adders->outputs;
      psumout = ports->name;
      ports = ports->next;
      pcout = ports->name;
  
      /* find the adder devices in the tech library */
      adds = (t_adder*)(hard_adders->instances);
      if (adds == NULL) /* No adders instantiated */
          return;
  
      /* simplified way of getting the multsize, but fine for quick example */
      while (adds != NULL) {
          /* write out this adder model TODO identical branches ?*/
          // if (configuration.fixed_hard_adder != 0)
          // 	count = fprintf(out, ".model adder\n");
          // else
          count = fprintf(out, ".model adder\n");
  
          /* add the inputs */
          count = count + fprintf(out, ".inputs");
          hard_add_inputs = adds->size_a + adds->size_b + adds->size_cin;
          for (i = 0; i < hard_add_inputs; i++) {
              if (i < adds->size_a) {
                  count = count + odin_sprintf(buffer, " %s[%d]", pa, i);
              } else if (i < hard_add_inputs - adds->size_cin && i >= adds->size_a) {
                  count = count + odin_sprintf(buffer, " %s[%d]", pb, i - adds->size_a);
              } else {
                  count = count + odin_sprintf(buffer, " %s[%d]", pcin, i - adds->size_a - adds->size_b);
              }
              if (count > 78)
                  count = fprintf(out, " \\\n %s", buffer) - 3;
              else
                  fprintf(out, " %s", buffer);
          }
          fprintf(out, "\n");
  
          /* add the outputs */
          count = fprintf(out, ".outputs");
          hard_add_outputs = adds->size_cout + adds->size_sumout;
          for (i = 0; i < hard_add_outputs; i++) {
              if (i < adds->size_cout) {
                  count = count + odin_sprintf(buffer, " %s[%d]", pcout, i);
              } else {
                  count = count + odin_sprintf(buffer, " %s[%d]", psumout, i - adds->size_cout);
              }
  
              if (count > 78) {
                  fprintf(out, " \\\n%s", buffer);
                  count = strlen(buffer);
              } else
                  fprintf(out, "%s", buffer);
          }
          fprintf(out, "\n");
          fprintf(out, ".blackbox\n");
          fprintf(out, ".end\n");
          fprintf(out, "\n");
  
          adds = adds->next;
      }
  }
  
  /*-------------------------------------------------------------------------
   * (function: define_add_function)
   *-----------------------------------------------------------------------*/
  void define_add_function(nnode_t* node, FILE* out) {
      int i, j;
      int count;
      char buffer[MAX_BUF];
  
      count = fprintf(out, "\n.subckt");
      count--;
      oassert(node->input_port_sizes[0] > 0);
      oassert(node->input_port_sizes[1] > 0);
      oassert(node->input_port_sizes[2] > 0);
      oassert(node->output_port_sizes[0] > 0);
      oassert(node->output_port_sizes[1] > 0);
  
      /* Write out th	bec_csla 	= 3 	// binary to excess carry Select Addere model adder  */
      count += fprintf(out, " adder");
  
      /* Write the input pins*/
      for (i = 0; i < node->num_input_pins; i++) {
          npin_t* driver_pin = node->input_pins[i]->net->driver_pin;
  
          if (i < node->input_port_sizes[0]) {
              if (!driver_pin->name)
                  j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->inputs->next->next->name, i, driver_pin->node->name);
              else
                  j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->inputs->next->next->name, i, driver_pin->name);
          } else if (i >= node->input_port_sizes[0] && i < node->input_port_sizes[1] + node->input_port_sizes[0]) {
              if (!driver_pin->name)
                  j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->inputs->next->name, i - node->input_port_sizes[0], driver_pin->node->name);
              else
                  j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->inputs->next->name, i - node->input_port_sizes[0], driver_pin->name);
          } else {
              if (!driver_pin->name)
                  j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->inputs->name, i - (node->input_port_sizes[0] + node->input_port_sizes[1]), driver_pin->node->name);
              else
                  j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->inputs->name, i - (node->input_port_sizes[0] + node->input_port_sizes[1]), driver_pin->name);
          }
  
          if (count + j > 79) {
              fprintf(out, "\\\n");
              count = 0;
          }
          count += fprintf(out, "%s", buffer);
      }
  
      /* Write the output pins*/
      for (i = 0; i < node->num_output_pins; i++) {
          if (i < node->output_port_sizes[0])
              j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->outputs->next->name, i, node->output_pins[i]->name);
          else
              j = odin_sprintf(buffer, " %s[%d]=%s", hard_adders->outputs->name, i - node->output_port_sizes[0], node->output_pins[i]->name);
          if (count + j > 79) {
              fprintf(out, "\\\n");
              count = 0;
          }
          count += fprintf(out, "%s", buffer);
      }
  
      fprintf(out, "\n\n");
      return;
  }
  
  /*-----------------------------------------------------------------------
   * (function: init_split_adder)
   * ##################################
   * TODO the soft logic adders can now be splitted at the source, we could tap onto that and merge these function for
   * simplicicity and would also make sure to keep the allocation at one place
   *###################################
   *	Create a carry chain adder when spliting. Inputs are connected
   *	to original pins, output pins are set to NULL for later connecting
   *	flag = 0: all adders are hard logic block; flag = 1: the last adder in the chain is soft logic block
   *---------------------------------------------------------------------*/
  void init_split_adder(nnode_t* node, nnode_t* ptr, int a, int sizea, int b, int sizeb, int cin, int cout, int index, int flag, netlist_t* netlist) {
      int i;
      int flaga = 0, flagb = 0;
      int current_sizea, current_sizeb;
      int aa = 0, bb = 0, num = 0;
  
      // if the input of the first cin is generated by a dummy adder added
      // to the start of the chain, then an offset is needed to compensate
      // for that in various positions in the code, otherwise the offset is 0
      const int offset = (configuration.adder_cin_global) ? 0 : 1;
  
      /* Copy properties from original node */
      ptr->type = node->type;
      ptr->bit_width = node->bit_width;
      ptr->related_ast_node = node->related_ast_node;
      ptr->traverse_visited = node->traverse_visited;
      ptr->node_data = NULL;
  
      /* decide the current size of input a and b */
      if (flag == 0) {
          // increase input sizes by one if a dummy adder is
          // added to feed the first cin in the chain
          current_sizea = (a + offset) - sizea * index;
          current_sizeb = (b + offset) - sizeb * index;
  
          if (current_sizea >= sizea)
              current_sizea = sizea;
          else if (current_sizea <= 0) {
              current_sizea = sizea;
              flaga = 1;
          } else {
              aa = current_sizea;
              current_sizea = sizea;
              flaga = 2;
          }
  
          if (current_sizeb >= sizeb)
              current_sizeb = sizeb;
          else if (current_sizeb <= 0) {
              current_sizeb = sizeb;
              flagb = 1;
          } else {
              bb = current_sizeb;
              current_sizeb = sizeb;
              flagb = 2;
          }
      } else {
          if (sizea != 0)
              current_sizea = sizea;
          else
              current_sizea = 1;
          if (sizeb != 0)
              current_sizeb = sizeb;
          else
              current_sizeb = 1;
      }
  
      /* Set new port sizes and parameters */
      ptr->num_input_port_sizes = 3;
      ptr->input_port_sizes = (int*)vtr::malloc(3 * sizeof(int));
      ptr->input_port_sizes[0] = current_sizea;
      ptr->input_port_sizes[1] = current_sizeb;
      ptr->input_port_sizes[2] = cin;
      ptr->num_output_port_sizes = 2;
      ptr->output_port_sizes = (int*)vtr::malloc(2 * sizeof(int));
      ptr->output_port_sizes[0] = cout;
  
      /* The size of output port sumout equals the maxim size of sizea and sizeb  */
      if (current_sizea > current_sizeb)
          ptr->output_port_sizes[1] = current_sizea;
      else
          ptr->output_port_sizes[1] = current_sizeb;
  
      /* Set the number of pins and re-locate previous pin entries */
      ptr->num_input_pins = current_sizea + current_sizeb + cin;
      ptr->input_pins = (npin_t**)vtr::malloc(sizeof(void*) * (current_sizea + current_sizeb + cin));
      //if flaga or flagb = 1, the input pins should be empty.
      if (flaga == 1) {
          for (i = 0; i < current_sizea; i++)
              ptr->input_pins[i] = NULL;
      } else if (flaga == 2) {
          if (index == 0) {
              ptr->input_pins[0] = NULL;
              if (sizea > 1) {
                  for (i = 1; i < aa; i++) {
                      ptr->input_pins[i] = node->input_pins[i + index * sizea - 1];
                      ptr->input_pins[i]->node = ptr;
                      ptr->input_pins[i]->pin_node_idx = i;
                  }
                  for (i = 0; i < (sizea - aa); i++)
                      ptr->input_pins[i + aa] = NULL;
              }
          } else {
              for (i = 0; i < aa; i++) {
                  ptr->input_pins[i] = node->input_pins[i + index * sizea - 1];
                  ptr->input_pins[i]->node = ptr;
                  ptr->input_pins[i]->pin_node_idx = i;
              }
              for (i = 0; i < (sizea - aa); i++)
                  ptr->input_pins[i + aa] = NULL;
          }
      } else {
          if (index == 0 && !configuration.adder_cin_global) {
              if (flag == 0) {
                  ptr->input_pins[0] = NULL;
                  if (current_sizea > 1) {
                      for (i = 1; i < current_sizea; i++) {
                          ptr->input_pins[i] = node->input_pins[i - 1];
                          ptr->input_pins[i]->node = ptr;
                          ptr->input_pins[i]->pin_node_idx = i;
                      }
                  }
              } else {
                  for (i = 0; i < current_sizea; i++) {
                      ptr->input_pins[i] = node->input_pins[i];
                      ptr->input_pins[i]->node = ptr;
                      ptr->input_pins[i]->pin_node_idx = i;
                  }
              }
          } else {
              if (flag == 0) {
                  for (i = 0; i < current_sizea; i++) {
                      // use the offset to compensate for the dummy adder added at start of the chain
                      ptr->input_pins[i] = node->input_pins[i + index * sizea - offset];
                      ptr->input_pins[i]->node = ptr;
                      ptr->input_pins[i]->pin_node_idx = i;
                  }
              } else {
                  if (sizea == 0)
                      connect_nodes(netlist->gnd_node, 0, ptr, 0);
                  else {
                      num = node->input_port_sizes[0];
                      for (i = 0; i < current_sizea; i++) {
                          ptr->input_pins[i] = node->input_pins[i + num - current_sizea];
                          ptr->input_pins[i]->node = ptr;
                          ptr->input_pins[i]->pin_node_idx = i;
                      }
                  }
              }
          }
      }
  
      if (flagb == 1) {
          for (i = 0; i < current_sizeb; i++)
              ptr->input_pins[i + current_sizeb] = NULL;
      } else if (flagb == 2) {
          if (index == 0) {
              ptr->input_pins[sizea] = NULL;
              if (current_sizeb > 1) {
                  for (i = 1; i < bb; i++) {
                      ptr->input_pins[i + current_sizea] = node->input_pins[i + a + index * sizeb - 1];
                      ptr->input_pins[i + current_sizea]->node = ptr;
                      ptr->input_pins[i + current_sizea]->pin_node_idx = i + current_sizea;
                  }
                  for (i = 0; i < (sizeb - bb); i++)
                      ptr->input_pins[i + current_sizea + bb] = NULL;
              }
          } else {
              for (i = 0; i < bb; i++) {
                  ptr->input_pins[i + current_sizea] = node->input_pins[i + a + index * sizeb - 1];
                  ptr->input_pins[i + current_sizea]->node = ptr;
                  ptr->input_pins[i + current_sizea]->pin_node_idx = i + current_sizea;
              }
              for (i = 0; i < (sizeb - bb); i++)
                  ptr->input_pins[i + current_sizea + bb] = NULL;
          }
      } else {
          if (index == 0 && !configuration.adder_cin_global) {
              if (flag == 0) {
                  ptr->input_pins[sizea] = NULL;
                  if (current_sizeb > 1) {
                      for (i = 1; i < current_sizeb; i++) {
                          ptr->input_pins[i + current_sizea] = node->input_pins[i + a + index * sizeb - 1];
                          ptr->input_pins[i + current_sizea]->node = ptr;
                          ptr->input_pins[i + current_sizea]->pin_node_idx = i + current_sizea;
                      }
                  }
              } else {
                  for (i = 0; i < current_sizeb; i++) {
                      ptr->input_pins[i + current_sizea] = node->input_pins[i + a];
                      ptr->input_pins[i + current_sizea]->node = ptr;
                      ptr->input_pins[i + current_sizea]->pin_node_idx = i + current_sizea;
                  }
              }
          } else {
              if (flag == 0) {
                  for (i = 0; i < current_sizeb; i++) {
                      ptr->input_pins[i + current_sizea] = node->input_pins[i + a + index * sizeb - offset];
                      ptr->input_pins[i + current_sizea]->node = ptr;
                      ptr->input_pins[i + current_sizea]->pin_node_idx = i + current_sizea;
                  }
              } else {
                  if (sizeb == 0)
                      connect_nodes(netlist->gnd_node, 0, ptr, current_sizea);
                  else {
                      num = node->input_port_sizes[0] + node->input_port_sizes[1];
                      for (i = 0; i < current_sizeb; i++) {
                          ptr->input_pins[i + current_sizea] = node->input_pins[i + num - current_sizeb];
                          ptr->input_pins[i + current_sizea]->node = ptr;
                          ptr->input_pins[i + current_sizea]->pin_node_idx = i + current_sizea;
                      }
                  }
              }
          }
      }
  
      /* Carry_in should be NULL*/
      for (i = 0; i < cin; i++) {
          ptr->input_pins[i + current_sizea + current_sizeb] = NULL;
      }
  
      /* output pins */
      int output;
      if (current_sizea > current_sizeb)
          output = current_sizea + cout;
      else
          output = current_sizeb + cout;
  
      ptr->num_output_pins = output;
      ptr->output_pins = (npin_t**)vtr::malloc(sizeof(void*) * output);
      for (i = 0; i < output; i++)
          ptr->output_pins[i] = NULL;
  
      return;
  }
  
  /*-------------------------------------------------------------------------
   * (function: split_adder)
   *
   * This function works to split a adder into several smaller
   *  adders to better "fit" with the available resources in a
   *  targeted FPGA architecture.
   *
   * This function is at the lowest level since it simply receives
   *  a adder and is told how to split it.
   *
   * Note: In this function, we can do padding(default -1), fix the size of hard block adder.
   *-----------------------------------------------------------------------*/
  
  void split_adder(nnode_t* nodeo, int a, int b, int sizea, int sizeb, int cin, int cout, int count, netlist_t* netlist) {
      nnode_t** node;
      int i, j;
      int num, lefta = 0, leftb = 0;
      int max_num = 0;
      int flag = 0;
  
      // if the input of the first cin is generated by a dummy adder added
      // to the start of the chain, then an offset is needed to compensate
      // for that in various positions in the code, otherwise the offset is 0
      const int offset = (configuration.adder_cin_global) ? 0 : 1;
  
      /* Check for a legitimate split */
      oassert(nodeo->input_port_sizes[0] == a);
      oassert(nodeo->input_port_sizes[1] == b);
  
      node = (nnode_t**)vtr::malloc(sizeof(nnode_t*) * (count));
  
      for (i = 0; i < count; i++) {
          node[i] = allocate_nnode();
          node[i]->name = (char*)vtr::malloc(strlen(nodeo->name) + 20);
          odin_sprintf(node[i]->name, "%s-%d", nodeo->name, i);
          if (i == count - 1) {
              //fixed_hard_adder = 1 then adder need to be exact size;
              if (configuration.fixed_hard_adder == 1)
                  init_split_adder(nodeo, node[i], a, sizea, b, sizeb, cin, cout, i, flag, netlist);
              else {
                  if (count == 1) {
                      lefta = a;
                      leftb = b;
                  } else {
                      lefta = (a + 1) % sizea;
                      leftb = (b + 1) % sizeb;
                  }
  
                  max_num = (lefta >= leftb) ? lefta : leftb;
                  // if fixed_hard_adder = 0, and the left of a and b is more than min_add, then adder need to be remain the same size.
                  if (max_num >= min_add)
                      init_split_adder(nodeo, node[i], a, sizea, b, sizeb, cin, cout, i, flag, netlist);
                  else {
                      // Using soft logic to do the addition, No need to pad as the same size
                      flag = 1;
                      init_split_adder(nodeo, node[i], a, lefta, b, leftb, cin, cout, i, flag, netlist);
                  }
              }
          } else
              init_split_adder(nodeo, node[i], a, sizea, b, sizeb, cin, cout, i, flag, netlist);
  
          //store the processed hard adder node for optimization
          processed_adder_list = insert_in_vptr_list(processed_adder_list, node[i]);
      }
  
      chain_information_t* adder_chain = allocate_chain_info();
      //if flag = 0, the last adder use soft logic, so the count of the chain should be one less
      if (flag == 0)
          adder_chain->count = count;
      else
          adder_chain->count = count - 1;
      adder_chain->num_bits = a + b;
      adder_chain->name = nodeo->name;
      chain_list = insert_in_vptr_list(chain_list, adder_chain);
  
      // don't add a dummy adder in the beginning of the chain if the first cin will be connected to a global gnd
      if ((flag == 0 || count > 1) && !configuration.adder_cin_global) {
          //connect the a[0] and b[0] of first adder node to ground
          connect_nodes(netlist->gnd_node, 0, node[0], 0);
          connect_nodes(netlist->gnd_node, 0, node[0], sizea);
          //hang the first sumout
          node[0]->output_pins[1] = allocate_npin();
          node[0]->output_pins[1]->name = append_string("", "%s~dummy_output~%d~%d", node[0]->name, 0, 1);
      }
  
      if (nodeo->num_input_port_sizes == 2) {
          //connect the first cin pin to unconn
          connect_nodes(netlist->pad_node, 0, node[0], node[0]->num_input_pins - 1);
      } else if (nodeo->num_input_port_sizes == 3) {
          //remap the first cin pins)
          remap_pin_to_new_node(nodeo->input_pins[nodeo->num_input_pins - 1], node[0], (node[0]->num_input_pins - 1));
      }
      //if (a + 1) % sizea == 0, the a[0] and b[0] of node[count-1] should connect to gound
      if ((a + 1) % sizea == 0 && (b + 1) % sizeb == 0) {
          if (flag == 0) {
              connect_nodes(netlist->gnd_node, 0, node[count - 1], 0);
              connect_nodes(netlist->gnd_node, 0, node[count - 1], sizea);
          }
      }
  
      //if any input pins beside first cin pins are NULL, connect those pins to unconn
      for (i = 0; i < count; i++) {
          num = node[i]->num_input_pins;
          for (j = 0; j < num - 1; j++) {
              if (node[i]->input_pins[j] == NULL)
                  connect_nodes(netlist->pad_node, 0, node[i], j);
          }
      }
  
      if (configuration.adder_cin_global) {
          // connect first cin to gnd
          connect_nodes(netlist->gnd_node, 0, node[0], (node[0]->num_input_pins - 1));
      }
  
      //connect cout to next cin
      for (i = 1; i < count; i++)
          connect_nodes(node[i - 1], 0, node[i], (node[i]->num_input_pins - 1));
  
      //remap the output pins of each adder to nodeo
      if (count == 1) {
          if (flag == 0) {
              for (j = 0; j < node[0]->num_output_pins - 2; j++) {
                  if (j < nodeo->num_output_pins)
                      remap_pin_to_new_node(nodeo->output_pins[j], node[0], j + 2);
                  else {
                      node[0]->output_pins[j + 2] = allocate_npin();
                      node[0]->output_pins[j + 2]->name = append_string("", "%s~dummy_output~%d~%d", node[0]->name, 0, j + 2);
                  }
                  //hang the first cout
                  node[0]->output_pins[0] = allocate_npin();
                  node[0]->output_pins[0]->name = append_string("", "%s~dummy_output~%d~%d", node[0]->name, 0, 0);
              }
          } else {
              for (j = 0; j < node[0]->num_output_pins - 1; j++)
                  remap_pin_to_new_node(nodeo->output_pins[j], node[0], j + 1);
              remap_pin_to_new_node(nodeo->output_pins[nodeo->num_output_pins - 1], node[0], 0);
          }
      } else {
          //First adder
          for (j = 0; j < node[0]->num_output_pins - 2; j++)
              remap_pin_to_new_node(nodeo->output_pins[j], node[0], j + 2);
          // if a dummy adder is added (offset = 1) start from the second adder)
          for (i = offset; i < count - 1; i++) {
              for (j = 0; j < node[i]->num_output_pins - 1; j++)
                  remap_pin_to_new_node(nodeo->output_pins[i * sizea + j - offset], node[i], j + 1);
          }
          //Last adder
          if (flag == 0) {
              for (j = 0; j < node[count - 1]->num_output_pins - 1; j++) {
                  // if a dummy adder is added to this chain (offset = 1), adjust the index of the adder using the offset constant
                  if (((count - 1) * sizea + j - offset) < nodeo->num_output_pins)
                      remap_pin_to_new_node(nodeo->output_pins[(count - 1) * sizea + j - offset], node[count - 1], j + 1);
                  else {
                      node[count - 1]->output_pins[j + 1] = allocate_npin();
                      // Pad outputs with a unique and descriptive name to avoid collisions.
                      node[count - 1]->output_pins[j + 1]->name = append_string("", "%s~dummy_output~%d~%d", node[count - 1]->name, count - 1, j + 1);
                  }
              }
              //Hang the last cout
              node[count - 1]->output_pins[0] = allocate_npin();
              // Pad outputs with a unique and descriptive name to avoid collisions.
              node[count - 1]->output_pins[0]->name = append_string("", "%s~dummy_output~%d~%d", node[count - 1]->name, count - 1, 0);
          } else {
              for (j = 0; j < node[count - 1]->num_output_pins - 1; j++)
                  //if(((count - 1) * sizea + j - 1) < nodeo->num_output_pins)
                  remap_pin_to_new_node(nodeo->output_pins[(count - 1) * sizea + j - 1], node[count - 1], j + 1);
              if (nodeo->output_pins[nodeo->num_output_pins - 1] != NULL)
                  remap_pin_to_new_node(nodeo->output_pins[nodeo->num_output_pins - 1], node[count - 1], 0);
              else {
                  node[count - 1]->output_pins[0] = allocate_npin();
                  // Pad outputs with a unique and descriptive name to avoid collisions.
                  node[count - 1]->output_pins[0]->name = append_string("", "%s~dummy_output~%d~%d", node[count - 1]->name, count - 1, 0);
              }
          }
      }
  
      /* Probably more to do here in freeing the old node! */
      vtr::free(nodeo->name);
      vtr::free(nodeo->input_port_sizes);
      vtr::free(nodeo->output_port_sizes);
  
      /* Free arrays NOT the pins since relocated! */
      vtr::free(nodeo->input_pins);
      vtr::free(nodeo->output_pins);
      vtr::free(nodeo);
      vtr::free(node);
      return;
  }
  
  /*-------------------------------------------------------------------------
   * (function: iterate_adders)
   *
   * This function will iterate over all of the add operations that
   *	exist in the netlist and perform a splitting so that they can
   *	fit into a basic hard adder block that exists on the FPGA.
   *	If the proper option is set, then it will be expanded as well
   *	to just use a fixed size hard adder.
   *-----------------------------------------------------------------------*/
  void iterate_adders(netlist_t* netlist) {
      int sizea, sizeb, sizecin; //the size of
      int a, b;
      int count, counta, countb;
      int num = 0;
      nnode_t* node;
  
      // offset to the adder size in case a dummy adder is added to
      // start of the adder chain to feed the first cin with gnd
      const int offset = (configuration.adder_cin_global) ? 0 : 1;
  
      /* Can only perform the optimisation if hard adders exist! */
      if (hard_adders == NULL)
          return;
      //In hard block adder, the summand and addend are same size.
      sizecin = hard_adders->inputs->size;
      sizeb = hard_adders->inputs->next->size;
      sizea = hard_adders->inputs->next->size;
  
      oassert(sizecin == 1);
  
      while (add_list != NULL) {
          node = (nnode_t*)add_list->data_vptr;
          add_list = delete_in_vptr_list(add_list);
          oassert(node != NULL);
          if (node->type == HARD_IP)
              node->type = ADD;
  
          oassert(node->type == ADD);
  
          a = node->input_port_sizes[0];
          b = node->input_port_sizes[1];
          num = (a >= b) ? a : b;
          node->bit_width = num;
          if (num >= min_threshold_adder && num >= min_add) {
              // if the first cin in a chain is fed by a global input (offset = 0) the adder width is the
              // input width + 1 (to pass the last cout -> sumout) divided by size of the adder input ports
              // otherwise (offset = 1) a dummy adder is added to the chain to feed the first cin with gnd
              // how many adders a can split
              counta = (a + 1) / sizea + offset;
              // how many adders b can split
              countb = (b + 1) / sizeb + offset;
              // how many adders need to be split
              if (counta >= countb)
                  count = counta;
              else
                  count = countb;
              total++;
              split_adder(node, a, b, sizea, sizeb, 1, 1, count, netlist);
          }
          // Store the node into processed_adder_list if the threshold is bigger than num
          else
              processed_adder_list = insert_in_vptr_list(processed_adder_list, node);
      }
      return;
  }
  
  /*-------------------------------------------------------------------------
   * (function: clean_adders)
   *
   * Clean up the memory by deleting the list structure of adders
   *	during optimization
   *-----------------------------------------------------------------------*/
  void clean_adders() {
      while (add_list != NULL)
          add_list = delete_in_vptr_list(add_list);
      return;
  }
  
  /*-------------------------------------------------------------------------
   * (function: reduce_operations)
   *
   * reduce the operations that are redundant
   *-----------------------------------------------------------------------*/
  void reduce_operations(netlist_t* /*netlist*/, operation_list op) {
      t_linked_vptr* place = NULL;
      operation_list oper;
      switch (op) {
          case ADD:
              place = add_list;
              oper = ADD;
              break;
  
          case MULTIPLY:
              place = mult_list;
              oper = MULTIPLY;
              break;
  
          case MINUS:
              place = sub_list;
              oper = MINUS;
              break;
  
          default:
              oper = NO_OP;
              break;
      }
  
      traverse_list(oper, place);
  }
  
  /*-------------------------------------------------------------------------
   * (function: traverse_list)
   *
   * traverse the operation lists
   *-----------------------------------------------------------------------*/
  void traverse_list(operation_list oper, t_linked_vptr* place) {
      while (place != NULL && place->next != NULL) {
          match_node(place, oper);
          place = place->next;
      }
  }
  
  /*---------------------------------------------------------------------------
   * (function: match_node)
   *-------------------------------------------------------------------------*/
  void match_node(t_linked_vptr* place, operation_list oper) {
      int flag = 0;
      int mark = 0;
      nnode_t* node = NULL;
      nnode_t* next_node = NULL;
      node = (nnode_t*)place->data_vptr;
      t_linked_vptr* pre = place;
      t_linked_vptr* next = NULL;
      if (place->next != NULL)
          next = place->next;
      while (next != NULL) {
          flag = 0;
          mark = 0;
          next_node = (nnode_t*)next->data_vptr;
          if (node->type == next_node->type) {
              if (node->num_input_pins == next_node->num_input_pins) {
                  flag = match_ports(node, next_node, oper);
                  if (flag == 1) {
                      mark = match_pins(node, next_node);
                      if (mark == 1) {
                          merge_nodes(node, next_node);
                          remove_list_node(pre, next);
                      }
                  }
              }
          }
          if (mark == 1)
              next = pre->next;
          else {
              pre = next;
              next = next->next;
          }
      }
  }
  
  /*---------------------------------------------------------------------------
   * (function: match_ports)
   *-------------------------------------------------------------------------*/
  int match_ports(nnode_t* node, nnode_t* next_node, operation_list oper) {
      int flag = 0;
      int sign = 0;
      int mark1 = 1;
      int mark2 = 1;
      ast_node_t *ast_node, *ast_node_next;
      char* component_s[2] = {0};
      char* component_o[2] = {0};
      ast_node = node->related_ast_node;
      ast_node_next = next_node->related_ast_node;
      if (ast_node->types.operation.op == oper) {
          traverse_operation_node(ast_node, component_s, oper, &sign);
          if (sign != 1) {
              traverse_operation_node(ast_node_next, component_o, oper, &sign);
              if (sign != 1) {
                  oassert(component_s[0] && component_o[0] && "missing children on operation");
                  switch (oper) {
                      case ADD:
                      case MULTIPLY: {
                          mark1 = strcmp(component_s[0], component_o[0]);
                          if (component_s[1] && component_o[1]) {
                              if (mark1 == 0) {
                                  mark2 = strcmp(component_s[1], component_o[1]);
                              } else {
                                  mark1 = strcmp(component_s[0], component_o[1]);
                                  mark2 = strcmp(component_s[1], component_o[0]);
                              }
                          }
                      } break;
  
                      case MINUS: {
                          mark1 = strcmp(component_s[0], component_o[0]);
                          if (mark1 == 0 && component_s[1] && component_o[1]) {
                              mark2 = strcmp(component_s[1], component_o[1]);
                          }
                      } break;
  
                      default:
  
                          break;
                  }
                  if (mark1 == 0 && mark2 == 0) {
                      flag = 1;
                  }
              }
          }
          for (int i = 0; i < ast_node->num_children; i++) {
              if (ast_node->children[i]->type != IDENTIFIERS) {
                  vtr::free(component_s[i]);
              }
          }
          for (int i = 0; i < ast_node_next->num_children; i++) {
              if (ast_node_next->children[i]->type != IDENTIFIERS) {
                  vtr::free(component_o[i]);
              }
          }
      }
  
      return flag;
  }
  
  /*-------------------------------------------------------------------------
   * (function: traverse_operation_node)
   *
   * search the ast find the couple of components
   *-----------------------------------------------------------------------*/
  void traverse_operation_node(ast_node_t* node, char* component[], operation_list op, int* mark) {
      long i;
  
      if (node == NULL)
          return;
  
      if (node->types.operation.op == op) {
          for (i = 0; i < node->num_children; i++) {
              *mark = 0;
              if (node->children[i]->type != IDENTIFIERS && node->children[i]->type != NUMBERS) {
                  *mark = 1;
                  break;
              } else {
                  if (node->children[i]->type == IDENTIFIERS) {
                      component[i] = node->children[i]->types.identifier;
                  } else if (node->children[i]->type == NUMBERS) {
                      long value = node->children[i]->types.vnumber->get_value();
                      long len = snprintf(NULL, 0, "%ld", value);
                      component[i] = (char*)vtr::calloc(len + 1, sizeof(char));
                      odin_sprintf(component[i], "%ld", value);
                  }
              }
          }
      }
  }
  
  /*---------------------------------------------------------------------------
   * (function: merge_node)
   *-------------------------------------------------------------------------*/
  void merge_nodes(nnode_t* node, nnode_t* next_node) {
      remove_fanout_pins(next_node);
      reallocate_pins(node, next_node);
      free_op_nodes(next_node);
  }
  
  /*---------------------------------------------------------------------------
   * (function: remove_list_node)
   *-------------------------------------------------------------------------*/
  void remove_list_node(t_linked_vptr* pre, t_linked_vptr* next) {
      if (next->next != NULL)
          pre->next = next->next;
      else
          pre->next = NULL;
      vtr::free(next);
  }
  
  /*---------------------------------------------------------------------------
   * (function: remove_fanout_pins)
   *-------------------------------------------------------------------------*/
  void remove_fanout_pins(nnode_t* node) {
      int i, j, k, idx;
      for (i = 0; i < node->num_input_pins; i++) {
          idx = node->input_pins[i]->unique_id;
          for (j = 0; j < node->input_pins[i]->net->num_fanout_pins; j++) {
              if (node->input_pins[i]->net->fanout_pins[j]->unique_id == idx)
                  break;
          }
          for (k = j; k < node->input_pins[i]->net->num_fanout_pins - 1; k++) {
              node->input_pins[i]->net->fanout_pins[k] = node->input_pins[i]->net->fanout_pins[k + 1];
              node->input_pins[i]->net->fanout_pins[k]->pin_net_idx = k;
          }
          node->input_pins[i]->net->fanout_pins[k] = NULL;
          node->input_pins[i]->net->num_fanout_pins--;
      }
  }
  
  /*---------------------------------------------------------------------------
   * (function: reallocate_pins)
   *-------------------------------------------------------------------------*/
  void reallocate_pins(nnode_t* node, nnode_t* next_node) {
      int i, j;
      int pin_idx;
      nnode_t* input_node = NULL;
      nnet_t* net = NULL;
      npin_t* pin = NULL;
      for (i = 0; i < next_node->num_output_pins; i++) {
          for (j = 0; j < next_node->output_pins[i]->net->num_fanout_pins; j++) {
              if (next_node->output_pins[i]->net->fanout_pins[j]->node != NULL) {
                  input_node = next_node->output_pins[i]->net->fanout_pins[j]->node;
                  net = node->output_pins[i]->net;
                  pin_idx = next_node->output_pins[i]->net->fanout_pins[j]->pin_node_idx;
                  pin = input_node->input_pins[pin_idx];
                  add_fanout_pin_to_net(net, pin);
              } else {
                  free_npin(next_node->output_pins[i]->net->fanout_pins[j]);
              }
          }
      }
  }
  
  /*---------------------------------------------------------------------------
   * (function: free_op_nodes)
   *-------------------------------------------------------------------------*/
  void free_op_nodes(nnode_t* node) {
      for (int i = 0; i < node->num_output_pins; i++) {
          if (node->output_pins[i]->net != NULL) {
              free_nnet(node->output_pins[i]->net);
          }
      }
      free_nnode(node);
  }
  
  /*---------------------------------------------------------------------------
   * (function: match_pins)
   *-------------------------------------------------------------------------*/
  int match_pins(nnode_t* node, nnode_t* next_node) {
      int flag = 0;
      int i, j;
      long id;
      for (i = 0; i < node->num_input_pins; i++) {
          flag = 0;
          id = node->input_pins[i]->net->driver_pin->unique_id;
          for (j = 0; j < next_node->num_input_pins; j++) {
              if (id == next_node->input_pins[j]->net->driver_pin->unique_id) {
                  flag = 1;
                  break;
              }
              if (j == next_node->num_input_pins - 1) {
                  flag = -1;
                  break;
              }
          }
          if (flag == -1)
              break;
      }
  
      return flag;
  }
  
  /*---------------------------------------------------------------------------------------------
   * connect adder type output pin to a node
   *-------------------------------------------------------------------------------------------*/
  static void connect_output_pin_to_node(int* width, int current_pin, int output_pin_id, nnode_t* node, nnode_t* current_adder, short subtraction) {
      // output
      if (subtraction) {
          remap_pin_to_new_node(node->output_pins[current_pin], current_adder, output_pin_id);
      } else {
          npin_t* node_pin_select = node->output_pins[(node->num_input_port_sizes == 2) ? current_pin : (current_pin < width[output_pin_id] - 1) ? current_pin + 1 : 0];
          if (node_pin_select->type != NO_ID || (node->num_input_port_sizes == 2)) {
              remap_pin_to_new_node(node_pin_select, current_adder, output_pin_id);
          } else {
              current_adder->output_pins[output_pin_id] = allocate_npin();
              current_adder->output_pins[output_pin_id]->name = append_string("", "%s~dummy_output~%d", current_adder->name, output_pin_id);
          }
      }
  }
  
  /*---------------------------------------------------------------------------------------------
   * make a single half-adder (can do unary subtraction, binary subtraction and addition)
   *-------------------------------------------------------------------------------------------*/
  static nnode_t* make_adder(operation_list funct, nnode_t* current_adder, nnode_t* previous_carry, int* width, int current_pin, netlist_t* netlist, nnode_t* node, short subtraction, short mark) {
      //make a 2 bit 0r 3 bit sum or carry based on previous carry
      nnode_t* new_funct = NULL;
      short is_three_port_gate = 0;
  
      if (previous_carry == netlist->gnd_node) {
          if (funct == ADDER_FUNC)
              new_funct = make_2port_gate(LOGICAL_XOR, 1, 1, 1, node, mark);
          else if (funct == CARRY_FUNC)
              new_funct = make_2port_gate(LOGICAL_AND, 1, 1, 1, node, mark);
      } else if (previous_carry == netlist->vcc_node) {
          if (funct == ADDER_FUNC)
              new_funct = make_2port_gate(LOGICAL_XNOR, 1, 1, 1, node, mark);
          else if (funct == CARRY_FUNC)
              new_funct = make_2port_gate(LOGICAL_OR, 1, 1, 1, node, mark);
      } else {
          new_funct = make_3port_gate(funct, 1, 1, 1, 1, node, mark);
          connect_nodes(previous_carry, 0, new_funct, 0);
          is_three_port_gate = 1;
      }
  
      //copy the input pin of a half-adder to another function (CARRY or ADDER)
      if (current_adder != NULL) {
          add_input_pin_to_node(new_funct, copy_input_npin(current_adder->input_pins[0 + is_three_port_gate]), 0 + is_three_port_gate);
          add_input_pin_to_node(new_funct, copy_input_npin(current_adder->input_pins[1 + is_three_port_gate]), 1 + is_three_port_gate);
      }
      // create one from scratch
      else {
          //connect input a
          if (current_pin < width[1]) {
              npin_t* temp_pin = node->input_pins[current_pin];
              if (temp_pin->net->driver_pin == NULL || temp_pin->net->driver_pin->node->type == GND_NODE) {
                  connect_nodes(netlist->gnd_node, 0, new_funct, 0 + is_three_port_gate);
                  remove_fanout_pins_from_net(temp_pin->net, temp_pin, temp_pin->pin_net_idx);
              } else if (temp_pin->net->driver_pin->node->type == VCC_NODE) {
                  connect_nodes(netlist->vcc_node, 0, new_funct, 0 + is_three_port_gate);
                  remove_fanout_pins_from_net(temp_pin->net, temp_pin, temp_pin->pin_net_idx);
              } else {
                  remap_pin_to_new_node(temp_pin, new_funct, 0 + is_three_port_gate);
              }
          } else {
              connect_nodes(netlist->gnd_node, 0, new_funct, 0 + is_three_port_gate);
          }
  
          //connect input b
          if (current_pin < width[2]) {
              //pin a is neighbor to pin b
              npin_t* temp_pin = node->input_pins[current_pin + width[1]];
              if (temp_pin->net->driver_pin == NULL || temp_pin->net->driver_pin->node->type == GND_NODE) {
                  nnode_t* attach_to = (subtraction) ? netlist->vcc_node : netlist->gnd_node;
                  connect_nodes(attach_to, 0, new_funct, 1 + is_three_port_gate);
                  remove_fanout_pins_from_net(temp_pin->net, temp_pin, temp_pin->pin_net_idx);
              } else if (temp_pin->net->driver_pin->node->type == VCC_NODE) {
                  nnode_t* attach_to = (subtraction) ? netlist->gnd_node : netlist->vcc_node;
                  connect_nodes(attach_to, 0, new_funct, 1 + is_three_port_gate);
                  remove_fanout_pins_from_net(temp_pin->net, temp_pin, temp_pin->pin_net_idx);
              } else {
                  if (subtraction) {
                      nnode_t* new_not_cells = make_not_gate(node, mark);
                      remap_pin_to_new_node(temp_pin, new_not_cells, 0);
                      connect_nodes(new_not_cells, 0, new_funct, 1 + is_three_port_gate);
                  } else {
                      remap_pin_to_new_node(temp_pin, new_funct, 1 + is_three_port_gate);
                  }
              }
          } else {
              nnode_t* attach_to = (subtraction) ? netlist->vcc_node : netlist->gnd_node;
              connect_nodes(attach_to, 0, new_funct, 1 + is_three_port_gate);
          }
      }
      return new_funct;
  }
  
  void instantiate_add_w_carry_block(int* width, nnode_t* node, short mark, netlist_t* netlist, short subtraction) {
      nnode_t* previous_carry = (subtraction) ? netlist->vcc_node : netlist->gnd_node;
  
      for (int i = 0; i < width[0]; i++) {
          /* set of flags for building purposes */
          short construct_last_carry_flag = (i != width[0] - 1 || !subtraction) ? 1 : 0;
  
          //build Ripple Carry Adder
          nnode_t* current_adder = make_adder(ADDER_FUNC, NULL, previous_carry, width, i, netlist, node, subtraction, mark);
          if (construct_last_carry_flag)
              previous_carry = make_adder(CARRY_FUNC, current_adder, previous_carry, width, i, netlist, node, subtraction, mark);
  
          connect_output_pin_to_node(width, i, 0, node, current_adder, subtraction);
      }
  }
  
  bool is_ast_adder(ast_node_t* node) {
      bool is_adder;
      ast_node_t* instance = node->children[1];
      is_adder = (!strcmp(node->children[0]->types.identifier, "adder"))
                 && (instance->children[1]->num_children == 5);
  
      ast_node_t* connect_list = instance->children[1];
      if (is_adder && connect_list->children[0]->children[0]) {
          /* port connections were passed by name; verify port names */
          for (int i = 0; i < connect_list->num_children && is_adder; i++) {
              char* id = connect_list->children[i]->children[0]->types.identifier;
  
              if ((strcmp(id, "a") != 0) && (strcmp(id, "b") != 0) && (strcmp(id, "cin") != 0) && (strcmp(id, "cout") != 0) && (strcmp(id, "sumout") != 0)) {
                  is_adder = false;
                  break;
              }
          }
      }
  
      return is_adder;
  }