/* GAMBIT Scheme program loader for M680x0 machines */

#include "params.h"
#include "gambit.h"
#include "struct.h"
#include "os.h"
#include "mem.h"
#include "strings.h"
#include "load.h"
#include "run.h"
#include "link.h"


/*---------------------------------------------------------------------------*/

/* Global data structures */

SSTATE_PTR sstate;  /* pointer to system state           */
PSTATE_PTR pstate;  /* pointer to this processor's state */


/*---------------------------------------------------------------------------*/


long gambit_argc;
char **gambit_argv, **gambit_envp;

long nb_args;

long nb_processors;
long stack_len, heap_len, const_len;
long remote, remote_stack, remote_heap, remote_intr;


void usage_err()
{ os_warn( "Usage: %s [arg]...\n", (long)gambit_argv[0] );
  os_warn( "           [--\n", 0L );
  os_warn( "            [-sSTACK_SIZE_IN_KILOBYTES]\n", 0L );
  os_warn( "            [-hHEAP_SIZE_IN_KILOBYTES]\n", 0L );
  os_warn( "            [-cCONST_SIZE_IN_KILOBYTES]\n", 0L );
  os_warn( "            [-d[DEBUG_LEVEL]]\n", 0L );
  os_warn( "            [-vGLOBAL_VARIABLE]...\n", 0L );
  os_warn( "            [-r[s][h][i]]\n", 0L );
  os_warn( "            [-p]\n", 0L );
  os_warn( "           ]\n", 0L );
  os_quit();
}


void main_gambit1();
void main_gambit2();
void main_gambit3();


void main_gambit( argc, argv, envp )
int argc;
char *argv[], *envp[];
{ gambit_argc = argc;
  gambit_argv = argv;
  gambit_envp = envp;
  main_gambit1();
}


void main_gambit1()
{ long i;

  remote = 0;
  remote_stack = 0;
  remote_heap = 0;
  remote_intr = 0;

  /* compute number of arguments to the program */

  nb_args = gambit_argc;
  for(i=1; i<gambit_argc; i++)
  { char *arg = gambit_argv[i];
    if ((arg[0] == '-') && (arg[1] == '-') && (arg[2] == '\0'))
    { nb_args = i; break; }
  }


  /* get size of stack, heap and constant area */

  if (link_stack_length_in_k < 0)
    stack_len = ((long)DEFAULT_STACK_LENGTH_IN_K)*K;
  else
    stack_len = link_stack_length_in_k*K;

  if (link_heap_length_in_k < 0)
    heap_len = ((long)DEFAULT_HEAP_LENGTH_IN_K)*K;
  else
    heap_len = link_heap_length_in_k*K;

  if (link_const_length_in_k < 0)
  { const_len = 0;
    for (i=0; i<link_nb_ofiles; i++) const_len += *(link_sizeof_ofiles[i]);
    const_len += ((long)ADDITIONAL_CONST_LENGTH_IN_K)*K;
  }
  else
    const_len = link_const_length_in_k*K;

  for(i=nb_args+1; i<gambit_argc; i++)
  { char *arg = gambit_argv[i];
    if (*arg == '-')
      switch (arg[1])
      { case 's': stack_len = string_to_int( &arg[2] )*K; break;
        case 'h': heap_len  = string_to_int( &arg[2] )*K; break;
        case 'c': const_len = string_to_int( &arg[2] )*K; break;
        case 'r': remote = 1;
                  arg += 2;
                  while (*arg != '\0')
                  switch (*arg++)
                  { case 's' : remote_stack = 1; break;
                    case 'h' : remote_heap  = 1; break;
                    case 'i' : remote_intr  = 1; break;
                    default  : usage_err();
                  }
      }
  }

  if (stack_len < ((long)MIN_STACK_LENGTH_IN_K)*K)
  { stack_len = ((long)MIN_STACK_LENGTH_IN_K)*K;
    os_warn( "Minimum size stack (%dK) is being allocated\n",
             (long)MIN_STACK_LENGTH_IN_K );
  }

  if (heap_len < ((long)MIN_HEAP_LENGTH_IN_K)*K)
  { heap_len = ((long)MIN_HEAP_LENGTH_IN_K)*K;
    os_warn( "Minimum size heap (%dK) is being allocated\n",
             (long)MIN_HEAP_LENGTH_IN_K );
  }


  /* setup global system memory */

  init_system_mem( main_gambit2 );
}


void main_gambit2( n )
long n;
{ long i;

  nb_processors = n;

  /* handle arguments */

  sstate->program_filename = gambit_argv[0];
  sstate->profiling = 0;
  sstate->debug = 0;

  for(i=nb_args+1; i<gambit_argc; i++)
  { char *arg = gambit_argv[i];
    if (*arg == '-')
    { if ((arg[1] == 's') || (arg[1] == 'h') || (arg[1] == 'c') || (arg[1] == 'r'))
        ;
      else if (arg[1] == 'd')
        if (arg[2] != '\0')
          sstate->debug = string_to_int( &arg[2] );
        else
          sstate->debug = 1;
      else if (arg[1] == 'v')
        ; /* will be handled later */
      else if (arg[1] == 'p')
        sstate->profiling = 1;
      else
        usage_err();
    }
    else
      usage_err();
  }


  /* setup each processor's memory */

  init_processor_mem( main_gambit3 );
}


void main_gambit3()
{ long i;
  void (*kernel)();

  /* setup table of object files to load */

  init_runtime();

  for (i=0; i<link_nb_ofiles; i++)
  { long size = *(link_sizeof_ofiles[i]);
    if (size < 0)
      ((void (*)())link_ofiles[i])();
    else
      init_ofile( (char *)(link_ofiles[i]), size );
  }


  /* load the program */

  kernel = (void (*)())init_program( nb_args, gambit_argv, gambit_envp );


  /* print value of global variables */

  for(i=nb_args+1; i<gambit_argc; i++)
  { char *arg = gambit_argv[i];
    if ((*arg == '-') && (arg[1] == 'v')) print_global_var( &arg[2] );
  }


  /* start executing the program */

  start_program( kernel );

  os_quit();
}


/*---------------------------------------------------------------------------*/
