// ds_arb_functions.c

#include "1394.h"
#include "data_structures.h"
#include "phy_services.h"
#include "arb.h"
#include "shared.h"

boolean fly_by_permitted() {            // TRUE if fly-by acceleration OK
  if (!link_CS_indications)
    return(FALSE);
  else if (receive_port == senior_port)
    return(FALSE);
  else if (req_speed == S100 && cur_speed != S100)
    return(FALSE);
  else if (breq == ISOCH_REQ)
    return(TRUE);
  else if (ack && accelerating)
    return(breq == PRIORITY_REQ || (breq == FAIR_REQ && arb_enable));
  else
    return(FALSE);
}

boolean Legacy_junior_request() {
  int i;
  for (i=0; i< NPORT; i++) {
    if (i != senior_port)
      if (portRarb[i] == LEGACY_REQUEST) {
        requesting_port = i;            // Found a junior that is requesting the bus
        grant_to_give = GRANT;
        return(TRUE);
      }
  }
  return (FALSE);
}

boolean data_coming_on(int port) {
  return (active[port] && 
          ((portRarb[port] == DATA_PREFIX) || 
          (portRarb[port] == DATA_NULL) || 
          (portRarb[port] == SPEED) ||
          (portRarb[port] == CYCLE_START_ODD) ||
          (portRarb[port] == CYCLE_START_EVEN)));
}

boolean data_coming() {
  int i;
  for (i = 0; i < NPORT; i++)
    if (data_coming_on(i)) {
      receive_port = i;               // Remember port for later...
      return(TRUE);
    }
  return(FALSE);
}

void Legacy_request_actions() {         // LEGACY_ARB request
  int i;
  if (!DS_stuck) {  
    max_beta_timer = 0;                 // timer  only needs to be implemented in border capable nodes
    DS_stuck = TRUE;                    // and note that this will have to be released by sending
                                        // a Legacy format packet
  }
  // following used when node re-enters A1 to do gap repeat actions
  if (send_async_start_token || arb_reset) {
    gap_repeat_actions(FALSE, senior_port);
    if (requesting_port != NPORT) portTarb(requesting_port, IDLE);
  }
  for (i = 0; i < NPORT; i++) {
    // Send data null to all non-requesting juniors
    if ((i != senior_port) && (i != requesting_port))
      portTarb(i, DATA_NULL);
  } 
  portTarb(senior_port, LEGACY_REQUEST);
}

boolean arb_OK() {                      // TRUE if OK to request the bus
  boolean async_arb_OK = FALSE;         // Timing window OK for asynchronous arbitration?

  if (DS_stuck) return (FALSE);         // Don't grant to or arbitrate for Legacy devices
                                        // stuck in receive

  if (arb_timer_max)
    async_arb_OK = TRUE;                // Arb timer previously saturated
  else {
    if (arb_timer < subaction_gap + arb_delay) // Only window for accelerations
      async_arb_OK = link_CS_indications && accelerating && ack;
    if (arb_timer >= subaction_gap && Legacy_junior_request())
      async_arb_OK = TRUE;                // Small window for stealing a child's request
    else if (arb_timer == subaction_gap + arb_delay)
      async_arb_OK = TRUE;                // Window for first fair request and priority requests
    else if (arb_timer >= arb_reset_gap + arb_delay)
      async_arb_OK = TRUE;                // Window for all requests (new fairness interval)
  }
  if (breq == ISOCH_REQ) {
    converted_request = FALSE;
    own_request = TRUE;
    requesting_port = NPORT;
    grant_to_give = GRANT_ISOCH;
  } else if (isoch_pending) {           // pipelined Beta isoch request to be forwarded
    converted_request = TRUE;
    own_request = (pending_port == NPORT);
    requesting_port = pending_port;
    grant_to_give = GRANT_ISOCH;
  } else if ((breq == PRIORITY_REQ) && async_arb_OK) {
    converted_request = FALSE;
    own_request = TRUE;
    requesting_port = NPORT;
    grant_to_give = GRANT;
  } else if ((breq == FAIR_REQ) && async_arb_OK && arb_enable) {
    converted_request = FALSE;
    own_request = TRUE;
    requesting_port = NPORT;
    grant_to_give = GRANT;
  } else if (async_pending && async_arb_OK) {
    converted_request = TRUE;
    own_request = (pending_port == NPORT);
    requesting_port = pending_port;
    grant_to_give = GRANT;
  } else {
    converted_request = FALSE;
    own_request = FALSE;
  }
  return(own_request || converted_request);
}

boolean LEGACY_GRANT() {
  return ((portRarb[senior_port] == GRANT) || (portRarb[senior_port] == GRANT_ISOCH));
}
