/*****************************************************************************

			       XCopilot

This code is part of XCopilot, a port of copilot

		  Copyright (C) 1997 Ivan A. Curtis
		       icurtis@radlogic.com.au

The original MS-Windows95 copilot emulator was written by Greg Hewgill.
The following copyright notice appeared on the original copilot sources:

		  Copyright (c) 1996 Greg Hewgill

 MC68000 Emulation code is from Bernd Schmidt's Unix Amiga Emulator.
       The following copyright notice appeared in those files:

	  Original UAE code Copyright (c) 1995 Bernd Schmidt

This code must not be distributed without these copyright notices intact.

*******************************************************************************
*******************************************************************************

Filename:	main.c

Description:	main file for xcopilot emulator

Update History:   (most recent first)
   I. Curtis   9-Apr-97 11:42 -- v0.4
   I. Curtis  18-Mar-97 14:00 -- v0.3
   I. Curtis  26-Feb-97 13:52 -- first release
   I. Curtis  23-Feb-97 20:43 -- Created.

******************************************************************************/

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "sysdeps.h"
#include "shared.h"
#include "memory.h"
#include "custom.h"
#include "newcpu.h"
#include "dragonball.h"

#include "display.h"
#include "pilotcpu.h"
#include "pdebug.h"

#define RAMSIZE 128		/* this is in k bytes */
#ifdef __sgi__
void usleep(long);
#endif
char *id_version = "XCopilot V0.4";

/*
 * These error messages correspond to the
 * codes in memory.h
 */
static const char *CpuInitErrors[] = {
  "",
  "pilot.rom file not found",
  "Error loading pilot.rom file",
  "Error loading pilot ram file",
};
/*****************************************************************************
 *                                                                           *
 * 			   Global variables                                  *
 *                                                                           *
 *****************************************************************************/
static shared_img *shptr;	/* pointer to the shared registers block */


/*********************************************
 * attach to the shared memory blocks        *
 * for the main memory and for the registers *
 * of the custom block                       *
 *********************************************/
void attach_shm(int shmid)
{
  void *s;
  s = shmat(shmid, (char *)0, 0);
  if (s == (void *)-1) {
    perror("shmat");
    exit(1);
  }
  shptr = (shared_img *)s;
  shptr->run_updateisr = 0;
  shptr->pen = 0;
  shptr->pendown = 0;
  shptr->CpuReq = cpuNone;
  shptr->kbin = 0;
  shptr->kbout = 0;
}

/*************************************
 * This is the CPU emulation process *
 *************************************/
void cpu_proc(int shmid)
{
  int r;
  attach_shm(shmid); /* get shared memory */
  r = CPU_init(shptr, RAMSIZE);
  if (r != 0) {
    fprintf(stderr, "E - %s\n", CpuInitErrors[r]);
    exit(1);
  }

  /*
   *   fprintf(stderr, "I - calling CPU..\n");
   *   fflush(stderr);
   */
  CPU(shptr);
  shmdt((char *)shptr);
  exit(0);
}

/*************************************
 * This is the LCD emulation process *
 *************************************/
void lcd_proc(int shmid, int no_x_shm)
{
  char *sbuf;
  attach_shm(shmid);                       /* get shared memory */
  memory_init(RAMSIZE);		                /* initialize memory */
  sbuf = xcpInitialize(no_x_shm); /* init xwindows */
  xcpEventLoop(sbuf, shptr);
  shmdt((char *)shptr);
  exit(0);
}

/********************************
 * This is the Debugger process *
 ********************************/
#define DEBUG_PORTNUM 2000
void debug_proc(int shmid, int do_debug)
{
  attach_shm(shmid);		/* get shared memory */
  memory_init(RAMSIZE);		/* initialize memory */
  MC68000_setshare(shptr);	/* initialize Shptr in newcpu module */

  if (do_debug) {
    pdebug_loop(DEBUG_PORTNUM, shptr);
    shptr->CpuReq = cpuExit;
  } else {
    usleep(1000);
    CPU_start(shptr);
    while (shptr->CpuReq != cpuExit) {
      usleep(1000000);
    }
  }
  shmdt((char *)shptr);
  exit(0);
}

void print_usage(char *name)
{
  fprintf(stderr, "usage %% %s [-uU] [-debug] [-noxshm]\n", name);
  fprintf(stderr, "\t-debug  => enter debug mode\n");
  fprintf(stderr, "\t-noxshm => don\'t use X Shared Mem, even if available\n");
}

/*****************************************************************************
 *                                                                           *
 * 		     Main - Execution starts here                            *
 *                                                                           *
 *****************************************************************************/
int main(int argc, char *argv[])
{
  int Debugging;		/* if TRUE, enter debugger */
  int NoXShm;			/* if TRUE, don't use X Shared Mem */
  int cpu_pid, display_pid;
  int shmid;

  /*
   *   fprintf(stderr, "%s\n", id_version);
   */

  /*
   * Process command line args
   */
  {
    int argno;
    Debugging = 0;
    NoXShm = 0;
    for (argno = 1; argno < argc; argno ++) {
      if (strcmp(argv[argno], "-u") == 0 || strcmp(argv[argno], "-U") == 0) {
	print_usage(argv[0]);
	exit(1);
      } else if (strcmp(argv[argno], "-debug") == 0) {
	Debugging = 1;
      } else if (strcmp(argv[argno], "-noxshm") == 0) {
	NoXShm = 1;
      } else {
	fprintf(stderr, "E - unknown arg \"%s\"\n", argv[argno]);
	print_usage(argv[0]);
	exit(1);
      }
    }
  }

  /*
   * get a shared memory segment
   */
  shmid = shmget((key_t) 0, sizeof(shared_img), IPC_CREAT | 0777);
  if (shmid < 0) {
    perror("shmget");
    exit(1);
  }

  /*
   * fork off the display process
   */
  display_pid = fork();
  if (display_pid < 0) {
    perror("display fork");
    exit(1);
  } else if (display_pid == 0) {
    lcd_proc(shmid, NoXShm);
  }

  /*
   * fork off the cpu process
   */
  cpu_pid = fork();
  if (cpu_pid < 0) {
    perror("cpu fork");
    exit(1);
  } else if (cpu_pid == 0) {
    cpu_proc(shmid);
  }

  /*
   * go do the debug process
   */
  debug_proc(shmid, Debugging);
  exit(0);
}
#ifdef __sgi__
#include <sys/time.h>
void usleep(long us) {
  struct timeval t;
  t.tv_usec = us;
  t.tv_sec = 0;
  select(0, 0, 0, 0, &t);
}
#endif
