/* make sure that this line is the first of emu.c
   and link emu.o as the first object file in the lib */
	__asm__("___START___: jmp _emulate\n");

/*
 * A DOS _emulation_ program.
 *
 * Copywrite 1993, Hamish Coleman (hamish@zot.apana.org.au)
 * This program is released under the terms of the GNU public
 * licence.  See the file COPYING for more information.
 *
 * This emulator was originally derived from an IBM emulation program
 * written by Matthias Lautner (lautner@informatik.uni-wuerzburg.de)
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <termio.h>
#include <termcap.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/times.h>
#include <sys/time.h>
#include <limits.h>
#include <linux/fd.h>
#include "global.h"
#include "emu.h"
#include "vm.h"
#include "bios.h"
#include "termio.h"
#include "msdos.h"

int do_screen_updates;
unsigned int next_upd;
FILE * fdeb;

void do_int(int i)
{
us *ssp;
	/* remember - these are emulated INTs - IE, they need to emulate_IRET .... */
	switch(i) {
#ifdef 0
		case 0x1b : /* BREAK */
		case 0x1c : /* TIMER */
		case 0x1d : /* SCREEN INIT */
		case 0x1e : /* DEF DISK PARMS */
		case 0x1f : /* DEF GRAPHIC */
		case 0x20 : /* EXIT */
		case 0x27 : /* TSR */
#endif
		case 0x20 : /* DOS - terminate */
			debmsg("Int_20 - Terminated.\n");
			error=10;
			break;
		case 0x21 : /* MS-DOS */
			msdos();
			break;
			/* else assume BIOS int .. */
		case 0x79: /* emulator int */
			switch (HI(ax)) {
				case 0x00:
					debmsg("Emulator installation check!\n");
					_regs.eax = 0x1234;
					break;
				case 0x01:
					debmsg("Emulator requested to stop!\n");
					error = 10;
					break;
				default:
					debmsg("Undefined emulator function\n");
					error = 1;
					break;
			}
			emulate_iret();
			break;
		default :
default_handling:
			do_bios_int(i);
	}
}

void do_hlt(void)
{
	 if ((_regs.cs & 0xffff) == 0xff01)     /* jump to an INT */
	  {
	  	/* debmsg("Execution at interrupt number 0x%02x\n",(_regs.eip & 0xffff)>>2); */
	  	do_int((_regs.eip & 0xffff) >>2);
	  } else
	  {
	  	debmsg("HLT instruction at 0x%04x:0x%04x\n",(_regs.cs & 0xffff),(_regs.eip & 0xffff));
	  }
	_regs.eflags &= ~RF; /* if we are debugging then we have done our resume .. */
	/*
	 * Have to scrutinize these Traceing flags ... 
	 */
}

int emulate(int argc, char **argv)
{
	unsigned int akt_t;

	sync(); /* for safety */

	/* init debugging file */
	fdeb = fopen(DEBUGFILE,"w");
	debmsg("\n\n\n*******************************\nEMULATE\n");
	
	/* init signal handlers */
	time(&start_time);
	termioInit();
/*
 * This makes it hard to use the emulator as a 'filter'
 
	clear_screen(screen, 7);
*/
	boot();
	boot_dos(argc,argv);
	fflush(stdout);
	SETIVEC(0x79,0xff01, 4*0x79);
	vm_prep();
	for(;!error;) {
		if (do_screen_updates) alarm(1);
		switch (vm()) {
			case F_sigsegv:
				fprintf(fdeb,"SIGSEGV:\n");
				show_regs();
				error = 1;
				break;
			case F_sigill:
				fprintf(fdeb,"SIGILL:\n");
				show_regs();
				error = 1;
				break;
			case F_mathem:
				fprintf(fdeb,"mathem:\n");
				show_regs();
				error = 1;
				break;
			case F_sigfpe:
				fprintf(fdeb,"SIGFPE:\n");
				show_regs();
				error = 1;
				break;
			case I_hlt:
				do_hlt();
				break;
			case I_lock:
				break;
			default:
		}
		do_bios_ticker();
		screen_bitfield |= vm86s.screen_bitmap; 
		if (do_screen_updates) alarm(0);
		akt_t = times(NULL);
		if (akt_t >= next_upd) {
			if (screen_bitfield) {
				restore_screen(screen_bitfield);
				akt_t = times(NULL);
			}
			next_upd = akt_t + UTICKS;
		}
	}
/*	printf("\n"); */
	termioClose();
	_exit(error);
}
