ftp.nice.ch/pub/next/tools/emulators/a2.N.bs.tar.gz#/a2/jump.c

This is jump.c in view mode; [Download] [Up]

/*
 *  a2, an Apple II emulator in C
 *  (c) Copyright 1990 by Rich Skrenta
 *
 *  Command line interface written by Tom Markson
 *
 *  Distribution agreement:
 *
 *	You may freely copy or redistribute this software, so long
 *	as there is no profit made from its use, sale, trade or
 *	reproduction.  You may not change this copyright notice,
 *	and it must be included prominently in any copy made.
 *
 *  Send emulator related mail to:  skrenta@blekko.commodore.com
 *				    skrenta@blekko.uucp
 */


#include	<stdio.h>
#include	<fcntl.h>
#include	"a2.h"

#define		jump_check(a,b,c,d)	(mem[Pc]==a && mem[Pc+1]==b && mem[Pc+2]==c && mem[Pc+3]==d)

/*
 *  In order to improve performance, we intercept the PC on JSR's
 *  and JMP's to certain locations and handled the intended function
 *  in C instead of letting the emulator interpret 6502.
 *
 *  This is done for video output, to produce an acceptable scroll;
 *  for the boot prom, so it crashes if there is no disk in the drive;
 *  and for other miscellaneous routines such as WAIT for speed.
 *
 *  In most cases the interceptor routine checks to see if the code it's
 *  intercepting looks like what it thinks should be there; it doesn't
 *  snatch the PC if the first four bytes of the routine don't match.
 */


#define		I_WAIT		1	/* defeat ROM WAIT routine           */
#define		I_PRODOS	2	/* Prodos high level intercept       */
#define		I_RWTS		3	/* DOS 3.3 high-level intercept      */
#define		I_BELL		4	/* don't toggle C030, output a bell  */
#define		I_VIDOUT	5	/* speeds up scrolling tremendously  */
#define		I_BOOT		6	/* crash if no disk on boot          */
#define		I_BOOTWAIT	7	/* defeat delay loops in DOS boot    */
#define		I_BOOTPATCH	8	/* patch dos for fast raw access     */


extern int map_to_upper;
extern unsigned char disk_ref();


set_special_jumps() {
  extern int set_c0();
  extern int set_writep();
  
  mem[0x43] = 0x60;			/* for ProDos boot */
  
  jmp_tbl[0xBD00] = I_RWTS;
  jmp_tbl[0xC600] = I_BOOT;
  jmp_tbl[0xC680] = I_PRODOS;	/* patched into boot prom below */
  jmp_tbl[0x9D84] = I_BOOTPATCH;	/* fast raw dos access */
  jmp_tbl[0xFBD9] = I_BELL;
  jmp_tbl[0xFBFD] = I_VIDOUT;
  jmp_tbl[0xFCA8] = I_WAIT;
  
  jmp_tbl[0x3A00] = I_BOOTWAIT;
  
  mem_set[0xC0] = set_c0;
  mem_set[0xC6] = set_writep;	/* write protect disk prom */
  
#if 0
  mem[0xC600] = 0;		/* flag for boot interception */
  mem[0xC601] = 0x20;		/* disk prom magic number */
  mem[0xC603] = 0x00;
  mem[0xC605] = 0x03;
  mem[0xC607] = 0x3C;
#endif
  
  /*
   *  Patch boot rom for fake Prodos driver
   */
  
  mem[0xC6FF] = 0x80;		/* C680 is driver address */
  mem[0xC6FE] = 0x1F;		/* info about device */
  
  screen_setup();
}


jump(key)
     int key;
{
  int i;
  
  switch (key) {
  case I_WAIT:					/* FCA8 */
    if (jump_check(0x38, 0x48, 0xE9, 0x01)) {
      A = 0;
      N = 0;
      V = 0;
      C = 1;
      DO_RTS;
    }
    break;
    
  case I_PRODOS:					/* C680 */
    prodos();
    break;
    
  case I_RWTS:					/* BD00 */
    if (jump_check(0x84, 0x48, 0x85, 0x49))
      rwts();
    break;
    
  case I_BELL:					/* FBD9 */
    if (jump_check(0x60, 0x87, 0xD0, 0x12)) {
      putchar(7);
      fflush(stdout);
      DO_RTS;
    }
    break;
    
  case I_VIDOUT:					/* FBFD */
    if (jump_check(0xC9, 0xA0, 0xB0, 0xEF))
      vidout();
    break;
    
  case I_BOOT:					/* C600 */
    if (disk[0] < 0) {
      info("boot: no disk");
      PCINC;			/* BRK into the monitor */
      push(high(Pc));
      push(low(Pc));
      B = 1;
      push(get_status());
      Pc = mem[0xFFFE] | (mem[0xFFFF] << 8);
      return;
    }
    info("boot");
    
    /* 
     *  We read the second half of a 512 byte block in case we're
     *  booting something that depends on this being a newer boot prom
     */
    
    drive = 0;
    read_disk(0, 14, &mem[0x900]);
    break;
    
    /*
     *  Standard DOS 3.3 has some pretty gross delay loops in its
     *  boot code.  The following patches defeat two of them.
     *  This could be dangerous; it seems to work, but DOS's original
     *  side effects are not maintained.  Comment out the jmp_tbl assignment
     *  of I_BOOTWAIT above if you are distrustful.
     *
     *  Interesting.  Dos relocates the patches when it moves into higher
     *  memory.  If you boot with a fast-booting dos that doesn't have the
     *  delays at 3A00, but still has them at BA00 & BD9E when it starts
     *  up, it will be slow if you turn off RWTS interception and use the
     *  raw interface.  However, slow-booting real DOS that gets patched
     *  while it's booting will have a faster raw interface, since it
     *  relocated the patches...
     */
    
  case I_BOOTWAIT:				/* 3A00 */
    if (jump_check(0xA2, 0x11, 0xCA, 0xD0)) {
      mem[0x3A00] = 0x60;		/* RTS */
      if (mem[0x3D9E] == 0xA0
	  &&  mem[0x3D9F] == 0x12
	  &&  mem[0x3DA0] == 0x88) {
	mem[0x3D9E] = 0x4C;	/* JMP past it */
	mem[0x3D9F] = 0xAB;
	mem[0x3DA0] = 0x3D;	/* gets relocated */
      }
    }
    break;
    
    /*
     *  This one is unnecessary since we do high-level RWTS interception
     */
    
  case I_BOOTPATCH:				/* 9D84 */
    if (jump_check(0xAD, 0xE9, 0xB7, 0x4A)) {
      if (mem[0xBA00] == 0xA2
	  &&  mem[0xBA01] == 0x11
	  &&  mem[0xBA02] == 0xCA) {
	mem[0xBA00] = 0x60;		/* RTS */
	if (mem[0xBD9E] == 0xA0
	    &&  mem[0xBD9F] == 0x12
	    &&  mem[0xBDA0] == 0x88) {
	  mem[0xBD9E] = 0x4C;
	  mem[0xBD9F] = 0xAB;
	  mem[0xBDA0] = 0xBD;
	}
      }
    }
    break;
    
  default:
    fprintf(stderr, "bad jump intercept key: %d\n", key);
    assert(FALSE);
  }
}


static int key_clear = TRUE;
static unsigned char last_key = 0;
static unsigned char temp_key;

extern int save_flags;

unsigned char
  mem_map(a)
unsigned short a;
{
  
  switch (a) {
  case 0xC000:
    if (key_clear) {
      fcntl (0, F_SETFL, save_flags | O_NDELAY);
      
      if (read (0, &temp_key, 1) == 1) {
	key_clear = FALSE;
	if (temp_key == '\n')
	  temp_key = '\r';
	else if (temp_key == 127)
	  temp_key = 8;
	if (map_to_upper)
	  temp_key = toupper(temp_key);
	last_key = temp_key | 0x80;
      }
      
      fcntl (0, F_SETFL, save_flags);
    }
    return(last_key);
    
  case 0xC010:
    key_clear = TRUE;
    last_key &= 0x7F;
    return(0);			/* what should this be? */
    
  case 0xC011:
    if (bank2_enable)
      return(0xFF);
    return(0x00);
    
  case 0xC012:
    if (ram_read)
      return(0xFF);
    return(0x00);
    
  case 0xC080: case 0xC081: case 0xC082: case 0xC083:
  case 0xC088: case 0xC089: case 0xC08A: case 0xC08B:
    ram_card(a);
    return(0x00);
    
    /*
     *  Slot 6 Disk II memory map 
     */
    
  case 0xC0E0: case 0xC0E1: case 0xC0E2: case 0xC0E3:
  case 0xC0E4: case 0xC0E5: case 0xC0E6: case 0xC0E7:
  case 0xC0E8: case 0xC0E9: case 0xC0EA: case 0xC0EB:
  case 0xC0EC: case 0xC0ED: case 0xC0EE: case 0xC0EF:
    return( disk_ref(a, 0) );
    
#if 0
    /*
     *  Keep the boot prom magic number from appearing if there is
     *  no disk in the drive
     */
    
  case 0xC600:
  case 0xC601:
    if (disk[0] < 0)
      return(0);
    break;
#endif
    
  }
  
  return(mem[a]);		/* default */
}


set_c0(a, n)
     unsigned short a;
     unsigned char n;
{
  
  switch (a & 0xFF) {
  case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15:
  case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B:
  case 0x1C: case 0x1D: case 0x1E: case 0x1F:
    key_clear = TRUE;
    last_key &= 0x7F;
    break;
    
  case 0x80: case 0x81: case 0x82: case 0x83:
  case 0x88: case 0x89: case 0x8A: case 0x8B:
    ram_card(a);
    break;
    
    /*
     *  Slot 6 Disk II memory map 
     */
    
  case 0xC0E0: case 0xC0E1: case 0xC0E2: case 0xC0E3:
  case 0xC0E4: case 0xC0E5: case 0xC0E6: case 0xC0E7:
  case 0xC0E8: case 0xC0E9: case 0xC0EA: case 0xC0EB:
  case 0xC0EC: case 0xC0ED: case 0xC0EE: case 0xC0EF:
    disk_ref(a, n);
    break;
    
  default:
    mem[a] = n;
  }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.