/*
 * Z80SIM  -  a	Z80-CPU	simulator
 *
 * Copyright (C) 1987-92 by Udo Munk
 *
 * This module of the Z80-CPU simulator must not be modified by a user,
 * see license agreement!
 *
 * History:
 * 28-SEP-87 Development on TARGON/35 with AT&T Unix System V.3
 * 11-JAN-89 Release 1.1
 * 08-FEB-89 Release 1.2
 * 13-MAR-89 Release 1.3
 * 09-FEB-90 Release 1.4 Ported to TARGON/31 M10/30
 * 20-DEC-90 Release 1.5 Ported to COHERENT 3.0
 * 10-JUN-92 Release 1.6 long casting problem solved with COHERENT 3.2
 *			 and some optimization
 * 25-JUN-92 Release 1.7 comments in english and ported to COHERENT 4.0
 */

/*
 *	This modul contain the 'main()' function of the simulator,
 *	where the options are checked and variables are initialized.
 *	After initialization of the UNIX interrupts ( int_on() )
 *	and initialization of the I/O simulation ( init_io() )
 *	the user interface ( mon() ) is called.
 */

#include <stdio.h>
#include <ctype.h>
#if defined(COHERENT) && !defined(_I386)
#include <sys/fcntl.h>
#else
#include <fcntl.h>
#endif
#ifndef COHERENT
#include <memory.h>
#endif
#include "sim.h"
#include "simglb.h"

main(argc, argv)
int argc;
char *argv[];
{
	void exit(), init_io(),	exit_io();
	register char *s, *p;
	register char *pn = argv[0];

	while (--argc >	0 && (*++argv)[0] == '-')
		for (s = argv[0] + 1; *s != '\0'; s++)
			switch (*s) {
			case 's':	/* save core and CPU on exit */
				s_flag = 1;
				break;
			case 'l':	/* load core and CPU from file */
				l_flag = 1;
				break;
			case 'h':	/* execute HALT opcode */
				break_flag = 0;
				break;
			case 'm':	/* initialize Z80 memory */
				m_flag = exatoi(s+1);
				s += strlen(s+1);
				break;
			case 'x':	/* get filename with Z80 executable */
				x_flag = 1;
				s++;
				p = xfn;
				while (*s)
					*p++ = *s++;
				*p = '\0';
				s--;
				break;
			default:
				printf("illegal option %c\n", *s);
				printf("usage:\t%s [-s -l -h -mn -xfilename]\n", pn);
				puts("\ts = save core and cpu");
				puts("\tl = load core and cpu");
				puts("\th = execute HALT op-code");
				puts("\tm = init memory with n");
				puts("\tx = load and execute filename");
				exit(1);
			}

	puts("#######  #####    ###            #####    ###   #     #");
	puts("     #  #     #  #   #          #     #    #    ##   ##");
	puts("    #   #     # #     #         #          #    # # # #");
	puts("   #     #####  #     #  #####   #####     #    #  #  #");
	puts("  #     #     # #     #               #    #    #     #");
	puts(" #      #     #  #   #          #     #    #    #     #");
	puts("#######  #####    ###            #####    ###   #     #");
	printf("\nRelease %s, %s\n", RELEASE, COPYR);
#ifdef	USR_COM
	printf("%s Release %s, %s\n", USR_COM, USR_REL,	USR_CPR);
#endif
	putchar('\n');
	fflush(stdout);

	wrk_ram	= PC = STACK = ram;
#ifdef COHERENT
	memset((char *)	ram, m_flag, 32767);
#else
	memset((char *)	ram, m_flag, 32768);
	memset((char *)	ram + 32768, m_flag, 32768);
#endif
	if (l_flag)
		load_core();
	int_on();
	init_io();
	mon();
	if (s_flag)
		save_core();
	exit_io();
	int_off();
	exit(0);
}

/*
 *	This function saves the CPU and the memory into the file core.z80
 *
 */
static save_core()
{
	int fd;

	if ((fd	= open("core.z80", O_WRONLY | O_CREAT, 0600)) == -1) {
		puts("can't open file core.z80");
		return;
	}
	write(fd, (char	*) &A, sizeof(A));
	write(fd, (char	*) &F, sizeof(F));
	write(fd, (char	*) &B, sizeof(B));
	write(fd, (char	*) &C, sizeof(C));
	write(fd, (char	*) &D, sizeof(D));
	write(fd, (char	*) &E, sizeof(E));
	write(fd, (char	*) &H, sizeof(H));
	write(fd, (char	*) &L, sizeof(L));
	write(fd, (char	*) &A_,	sizeof(A_));
	write(fd, (char	*) &F_,	sizeof(F_));
	write(fd, (char	*) &B_,	sizeof(B_));
	write(fd, (char	*) &C_,	sizeof(C_));
	write(fd, (char	*) &D_,	sizeof(D_));
	write(fd, (char	*) &E_,	sizeof(E_));
	write(fd, (char	*) &H_,	sizeof(H_));
	write(fd, (char	*) &L_,	sizeof(L_));
	write(fd, (char	*) &I, sizeof(I));
	write(fd, (char	*) &IFF, sizeof(IFF));
	write(fd, (char	*) &R, sizeof(R));
	write(fd, (char	*) &PC,	sizeof(PC));
	write(fd, (char	*) &STACK, sizeof(STACK));
	write(fd, (char	*) &IX,	sizeof(IX));
	write(fd, (char	*) &IY,	sizeof(IY));
#ifdef COHERENT
	write(fd, (char *) ram, 32767);
#else
	write(fd, (char	*) ram,	32768);
	write(fd, (char	*) ram + 32768,	32768);
#endif
	close(fd);
}

/*
 *	This function loads the CPU and memory from the file core.z80
 *
 */
static load_core()
{
	int fd;

	if ((fd	= open("core.z80", O_RDONLY)) == -1) {
		puts("can't open file core.z80");
		return;
	}
	read(fd, (char *) &A, sizeof(A));
	read(fd, (char *) &F, sizeof(F));
	read(fd, (char *) &B, sizeof(B));
	read(fd, (char *) &C, sizeof(C));
	read(fd, (char *) &D, sizeof(D));
	read(fd, (char *) &E, sizeof(E));
	read(fd, (char *) &H, sizeof(H));
	read(fd, (char *) &L, sizeof(L));
	read(fd, (char *) &A_, sizeof(A_));
	read(fd, (char *) &F_, sizeof(F_));
	read(fd, (char *) &B_, sizeof(B_));
	read(fd, (char *) &C_, sizeof(C_));
	read(fd, (char *) &D_, sizeof(D_));
	read(fd, (char *) &E_, sizeof(E_));
	read(fd, (char *) &H_, sizeof(H_));
	read(fd, (char *) &L_, sizeof(L_));
	read(fd, (char *) &I, sizeof(I));
	read(fd, (char *) &IFF,	sizeof(IFF));
	read(fd, (char *) &R, sizeof(R));
	read(fd, (char *) &PC, sizeof(PC));
	read(fd, (char *) &STACK, sizeof(STACK));
	read(fd, (char *) &IX, sizeof(IX));
	read(fd, (char *) &IY, sizeof(IY));
#ifdef COHERENT
	read(fd, (char *) ram, 32767);
#else
	read(fd, (char *) ram, 32768);
	read(fd, (char *) ram +	32768, 32768);
#endif
	close(fd);
}
