/* 
   Pcm: a PC eMulator
   Copyright (C) 1992 Electronetics, Inc.  All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>

#if defined(sun) || defined(apollo)
#define BIG_ENDIAN 1
#endif

/* #define READ_TIME 1 */

extern unsigned char pc_mem[0x10fff0]; /* pc memory, no segment wrap */

extern union {
  unsigned int i;
  unsigned short s[2];
  unsigned char c[4];
  void (*fptr)();
  unsigned char *cptr;
} qmem[128];  /* Memory that can be accessed easily */

extern struct {
  int fd;  /* The file descriptor for this drive */
  int heads;
  int tracks;
  int sectors; /* sectors per track */
  int readonly;
  unsigned devicep : 1; /* True if this is a real floppy */
} disk[4];

extern int numdrives;
extern unsigned short flagshort;

/*
 * Registers are implemented in Big-Endian
 * order on Big-Endian machines to simplify
 * effective address computation.
 */

#define AX qmem[0].s[0]
#define CX qmem[0].s[1]
#define DX qmem[1].s[0]
#define BX qmem[1].s[1]
#define SP  qmem[2].s[0]
#define BP  qmem[2].s[1]
#define SI  qmem[3].s[0]
#define DI  qmem[3].s[1]

#ifdef BIG_ENDIAN
#define AH qmem[0].c[0]
#define AL qmem[0].c[1]
#define CH qmem[0].c[2]
#define CL qmem[0].c[3]
#define DH qmem[1].c[0]
#define DL qmem[1].c[1]
#define BH qmem[1].c[2]
#define BL qmem[1].c[3]
#define SPH qmem[2].c[0]
#define SPL qmem[2].c[1]
#define BPH qmem[2].c[2]
#define BPL qmem[2].c[3]
#define SIH qmem[3].c[0]
#define SIL qmem[3].c[1]
#define DIH qmem[3].c[2]
#define DIL qmem[3].c[3]
#define CSH qmem[4].c[0]
#define CSL qmem[4].c[1]
#define DSH qmem[4].c[2]
#define DSL qmem[4].c[3]
#define ESH qmem[5].c[0]
#define ESL qmem[5].c[1]
#define SSH qmem[5].c[2]
#define SSL qmem[5].c[3]
#else
#define AL qmem[0].c[0]
#define AH qmem[0].c[1]
#define CL qmem[0].c[2]
#define CH qmem[0].c[3]
#define DL qmem[1].c[0]
#define DH qmem[1].c[1]
#define BL qmem[1].c[2]
#define BH qmem[1].c[3]
#define SPL qmem[2].c[0]
#define SPH qmem[2].c[1]
#define BPL qmem[2].c[2]
#define BPH qmem[2].c[3]
#define SIL qmem[3].c[0]
#define SIH qmem[3].c[1]
#define DIL qmem[3].c[2]
#define DIH qmem[3].c[3]
#define CSL qmem[4].c[0]
#define CSH qmem[4].c[1]
#define DSL qmem[4].c[2]
#define DSH qmem[4].c[3]
#define ESL qmem[5].c[0]
#define ESH qmem[5].c[1]
#define SSL qmem[5].c[2]
#define SSH qmem[5].c[3]
#endif /* BIG_ENDIAN */

#define CS  qmem[4].s[0]
#define DS  qmem[4].s[1]
#define ES  qmem[5].s[0]
#define SS  qmem[5].s[1]

#define CSPTR qmem[6].cptr
#define DSPTR qmem[7].cptr
#define ESPTR qmem[8].cptr
#define SSPTR qmem[9].cptr

/* Pointer to the register operand */
#define REGPTR qmem[10].cptr
/* Pointer to the effective address operand */
#define EAPTRL  qmem[11].cptr
#define EAPTRH  qmem[12].cptr

#ifdef BIG_ENDIAN
#define _AH 0
#define _AL 1
#define _CH 2
#define _CL 3
#define _DH 4
#define _DL 5
#define _BH 6
#define _BL 7
#define REGPTRL (REGPTR+1)
#define REGPTRH REGPTR
#else
#define _AH 1
#define _AL 0
#define _CH 3
#define _CL 2
#define _DH 5
#define _DL 4
#define _BH 7
#define _BL 6
#define REGPTRL REGPTR
#define REGPTRH (REGPTR+1)
#endif /* BIG_ENDIAN */

#define CARRY      qmem[13].c[0]
#define PARITY     qmem[13].c[1]
#define AUXILIARY  qmem[14].c[2]
#define ZERO       qmem[14].c[3]
#define SIGN       qmem[14].c[0]
#define TRAP       qmem[14].c[1]
#define INTERRUPT  qmem[15].c[2]
#define DIRECTION  qmem[15].c[3]
#define OVERFLOW   qmem[15].c[0]
#define FLAGS_OK   qmem[15].c[1]
/* qmem[14]+2,3 unused */

/* flag macros */
#define PFLAG4(w,x,y,z) FL1 = w; FL2 = x; \
  FL3 = y; FL4 = z; FLAGS_OK = 0

#define PFLAG3(x,y,z) FL1 = x; FL2 = y; FL4 = z; \
  FLAGS_OK = 0

#define PFLAG2(x,y) FL1 = x; FL4 = y; FLAGS_OK = 0

#define PFLAG1(x) FL4 = x; FLAGS_OK = 0

#define FL1    qmem[16].s[0]
#define FL2    qmem[16].s[1]
#define FL3    qmem[17].s[0]
#define FL4    qmem[17].s[1]

#ifdef BIG_ENDIAN
#define FL1H   qmem[16].c[0]
#define FL1L   qmem[16].c[1]
#define FL2H   qmem[16].c[2]
#define FL2L   qmem[16].c[3]
#else
#define FL1L   qmem[16].c[0]
#define FL1H   qmem[16].c[1]
#define FL2L   qmem[16].c[2]
#define FL2H   qmem[16].c[3]
#endif /* BIG_ENDIAN */

#define ADDW       1
#define WBOOL      2
#define CBOOL      3
#define ADCB       4
#define SBBB       5
#define SUBB       6
#define ADDB       7
#define SUBW       8
#define DECW       9
#define INCB      10
#define DECB      11
#define INCW      12
#define ADCW      13
#define SBBW      14

#define TIMELEFT   qmem[18].i

/*
 * Copies of DSPTR, SSPTR to be used for
 * effective address calculation.  Overridden
 * by segment override.
 */
#define TSTART 19
#define DSEA qmem[19].cptr
#define SSEA qmem[20].cptr

/*
 * Add new globals here
 */

#define DATA  0
#define STACK 1

#define EADDR1(seg, off) \
  EAPTRL = qmem[seg+TSTART].cptr + (unsigned short)(off); \
  EAPTRH = EAPTRL+1

#define EADDR2(seg, off) \
  LOADW2(offset,pc++);\
  EAPTRL = qmem[seg+TSTART].cptr + (unsigned short)(off + offset); \
  EAPTRH = EAPTRL+1

#define EADDR3(seg, off) \
  EAPTRL = qmem[seg+TSTART].cptr +           \
    (unsigned short)(*(char *)pc++ + off);  \
  EAPTRH = EAPTRL+1

#ifdef BIG_ENDIAN
#define EADDR4(reg) EAPTRH = (unsigned char *)&(reg); EAPTRL = EAPTRH+1
#else
#define EADDR4(reg) EAPTRL = (unsigned char *)&(reg); EAPTRH = EAPTRL+1
#endif /* BIG_ENDIAN */

#define EADDR5(seg, off) \
  EAPTRL = qmem[seg+TSTART].cptr + ((unsigned short)(off))

#define EADDR6(seg, off) \
  LOADW2(offset,pc++);                           \
  EAPTRL = qmem[seg+TSTART].cptr + ((unsigned short)(off + offset))

#define EADDR7(seg, off) \
  EAPTRL = qmem[seg+TSTART].cptr + ((unsigned short)(*(char *)pc++ + off))

#define EADDR8(low,index) EAPTRL = &low;

#define SETDS DSEA = DSPTR = pc_mem + ((unsigned int)DS << 4)

#define SETES ESPTR = pc_mem + ((unsigned int)ES << 4)

#define SETSS SSEA = SSPTR = pc_mem + ((unsigned int)SS << 4)

#define LOADW2(dest,ptr) \
  dest = *(unsigned char *)(ptr); \
  dest |= (unsigned int)*((unsigned char *)(ptr)) << 8;

#define HIGH(shrt) (*(unsigned char *)&(shrt))
#define LOW(shrt)  (*((unsigned char *)&(shrt)+1))

/*
 * Bios #defines
 */
#define CUR_PAGE pc_mem[0x462]
#define CUR_X pc_mem[0x450+(CUR_PAGE << 1)]
#define CUR_Y pc_mem[0x451+(CUR_PAGE << 1)]

unsigned char *word_operand(), *byte_operand(), *word_operand2();
unsigned char *interrupt(), *unk_op(), *i_esc();

unsigned char *i_00(),*i_01(),*i_02(),*i_03(),*i_04(),*i_05(),*i_06(),*i_07();
unsigned char *i_08(),*i_09(),*i_0a(),*i_0b(),*i_0c(),*i_0d(),*i_0e(),*i_0f();

unsigned char *i_10(),*i_11(),*i_12(),*i_13(),*i_14(),*i_15(),*i_16(),*i_17();
unsigned char *i_18(),*i_19(),*i_1a(),*i_1b(),*i_1c(),*i_1d(),*i_1e(),*i_1f();

unsigned char *i_20(),*i_21(),*i_22(),*i_23(),*i_24(),*i_25(),*i_26(),*i_27();
unsigned char *i_28(),*i_29(),*i_2a(),*i_2b(),*i_2c(),*i_2d(),*i_2e();

unsigned char *i_30(),*i_31(),*i_32(),*i_33(),*i_34(),*i_35(),*i_36(),*i_37();
unsigned char *i_38(),*i_39(),*i_3a(),*i_3b(),*i_3c(),*i_3d(),*i_3e();

unsigned char *i_40(),*i_41(),*i_42(),*i_43(),*i_44(),*i_45(),*i_46(),*i_47();
unsigned char *i_48(),*i_49(),*i_4a(),*i_4b(),*i_4c(),*i_4d(),*i_4e(),*i_4f();

unsigned char *i_50(),*i_51(),*i_52(),*i_53(),*i_54(),*i_55(),*i_56(),*i_57();
unsigned char *i_58(),*i_59(),*i_5a(),*i_5b(),*i_5c(),*i_5d(),*i_5e(),*i_5f();

unsigned char *i_70(),*i_71(),*i_72(),*i_73(),*i_74(),*i_75(),*i_76(),*i_77();
unsigned char *i_78(),*i_79(),*i_7a(),*i_7b(),*i_7c(),*i_7d(),*i_7e(),*i_7f();

unsigned char *i_80(),*i_81(),*i_83(),*i_84(),*i_85(),*i_86(),*i_87();
unsigned char *i_88(),*i_89(),*i_8a(),*i_8b(),*i_8c(),*i_8d(),*i_8e(),*i_8f();

unsigned char *i_90(),*i_91(),*i_92(),*i_93(),*i_94(),*i_95(),*i_96(),*i_97();
unsigned char *i_98(),*i_99(),*i_9a(),*i_9b(),*i_9c(),*i_9d(),*i_9e(),*i_9f();

unsigned char *i_a0(),*i_a1(),*i_a2(),*i_a3(),*i_a4(),*i_a5(),*i_a6(),*i_a7();
unsigned char *i_a8(),*i_a9(),*i_aa(),*i_ab(),*i_ac(),*i_ad(),*i_ae(),*i_af();

unsigned char *i_b0(),*i_b1(),*i_b2(),*i_b3(),*i_b4(),*i_b5(),*i_b6(),*i_b7();
unsigned char *i_b8(),*i_b9(),*i_ba(),*i_bb(),*i_bc(),*i_bd(),*i_be(),*i_bf();

unsigned char *i_c2(),*i_c3(),*i_c4(),*i_c5(),*i_c6(),*i_c7();
unsigned char *i_ca(),*i_cb(),*i_cc(),*i_cd(),*i_ce(),*i_cf();

unsigned char *i_d0(),*i_d1(),*i_d2(),*i_d3(),*i_d4(),*i_d5(),*i_d7();

unsigned char *i_e0(),*i_e1(),*i_e2(),*i_e3(),*i_e4(),*i_e5(),*i_e6();
unsigned char *i_e8(),*i_e9(),*i_ea(),*i_eb(),*i_ec(),*i_ed(),*i_ee(),*i_ef();

unsigned char *i_f0(),*i_f2(),*i_f3(),*i_f4(),*i_f5(),*i_f6(),*i_f7();
unsigned char *i_f8(),*i_f9(),*i_fa(),*i_fb(),*i_fc(),*i_fd(),*i_fe(),*i_ff();

unsigned char *int_08(),*int_16();
void int_09();
void int_10(),int_11(),int_12(),int_13(),int_14(),int_15(),int_17(),int_1a();
unsigned char *int_19(), *init_bios(), *interpret();
#ifdef notdef
unsigned char *atomic_interpret();
#endif
unsigned char *do_interrupt();
void fblcopy(),bblcopy(),do_compute_flags();
extern int debug;

#define compute_flags()  { if (!FLAGS_OK) do_compute_flags(); }
	
#ifdef READ_TIME
FILE *trfile;
#endif /* READ_TIME */

#ifdef WRITE_TIME
FILE *twfile;
#endif /* WRITE_TIME */

/*
 * We define atomic_interrupt as an "inline function" if our C
 * compiler allows it.  Otherwise, we rely on pre-processor magic.
 */
extern unsigned char *(*ifun[256])();
#ifdef HAVE_INLINE_FUNCS
inline unsigned char *atomic_interpret(ip)
unsigned char *ip; {
  return (*ifun[*ip])(ip+1);
}
#else
#define atomic_interpret(ip) ((*ifun[*(ip)])((ip)+1))
#endif

/*
 * Interrupts for network drive operation
 */
#define NETWRK 0xfe
#define MULTIPLEX 0x2f

unsigned char *lol; /* DOS list of lists */
unsigned char *sda; /* Swappable data area */
unsigned char *sdb; /* Search data block */
unsigned char *sft; /* System file table */
unsigned char *cds; /* Current directory structure */
unsigned char dos_major, dos_minor;
unsigned char *cptr;

