# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # This archive contains: # cli.c cli.h commands.c dos.c # hex.c jump.c main.c mapper.c # mem.c parse.c prodos.c screen.c # table.c vidout.c # echo x - cli.c cat >cli.c <<'@EOF' /* * 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 #include #include #include "a2.h" #include "cli.h" FILE *logging_fp = NULL; long breakpoint = -1; long trace_lo = -1; long trace_hi; int in_cli; unsigned short lpoint; /* point where dissassembly occurs */ long phantom_location = -1; int map_to_upper = 1; jmp_buf jb; cli_catch() { signal(SIGINT,cli_catch); printf("\n"); longjmp(jb,1); } cli() { char foo[200]; restore_term(); MoveCursor(term_lines, 0); status(stdout); in_cli = TRUE; lpoint = Pc; signal(SIGINT, cli_catch); setjmp(jb); do { printf(">>>"); if (fgets(foo, 200, stdin) == NULL) { printf("\n"); exit(0); } foo[strlen(foo)-1] = '\0'; if (parse(first_tbl, foo)) { running = FALSE; tracing = FALSE; return; /* single step; no redraw */ } } while (in_cli); set_term(); redraw_screen(); if (breakpoint != -1 || trace_lo != -1) { tracing = TRUE; running = FALSE; } else { tracing = FALSE; running = TRUE; } } status(fp) FILE *fp; { diss(Pc, fp); flags(fp); } @EOF chmod 644 cli.c echo x - cli.h cat >cli.h <<'@EOF' /* * 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 */ /* * Return codes for match(), find_box(), and parse() */ #define NO_MATCH -1 /* strings are different */ #define PARTIAL -3 /* partial match */ #define IDENTICAL -4 /* strings matched perfectly */ #define AMBIGUOUS -2 /* amiguous match */ #define OK -5 /* command executed ok */ #define NOT_IMPLEMENTED -6 /* haven't written this one yet */ #define DISPLAY -7 /* redisplay the diss & flags line */ #define MAXSTACK 100 struct cmdtbl { char *name; int (*func)(); }; extern long breakpoint; extern struct cmdtbl first_tbl[]; extern int in_cli; extern long trace_lo, trace_hi; extern long get_hex_number(); extern FILE *logging_fp; extern char *getenv(); extern char *split(); @EOF chmod 644 cli.h echo x - commands.c cat >commands.c <<'@EOF' /* * 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 #include #include #include "a2.h" #include "cli.h" extern unsigned short lpoint; extern long phantom_location; extern char *getcwd(); extern int map_to_upper; extern char escape_char; long get_hex_number(); char diskname[2][200]; /* disk names stored here */ struct point_stack { unsigned short data[MAXSTACK]; int sp; } pstack; init_point(){ pstack.sp = -1; } pop_point(rest) char *rest; { if (pstack.sp < 0 ) { printf("stack empty\n"); return OK; } switch (*rest){ case 'l': case 'L': printf("%x\n", lpoint = pstack.data[pstack.sp--]); break; case 'p': case 'P': printf("%x\n", lpoint = pstack.data[pstack.sp--]); break; default : printf("pop [lp]\n"); break; } return(OK); } dup_point(rest) char *rest; { if (pstack.sp < 0 ) { printf("stack empty\n"); return OK; } switch (*rest){ case 'l': case 'L': lpoint = pstack.data[pstack.sp]; break; case 'p': case 'P': lpoint = pstack.data[pstack.sp]; break; default : printf("dup [lp]\n"); break; } return(OK); } push_point(rest) char *rest; { long value; char *addr; assert (pstack.sp < MAXSTACK); switch (*rest){ case 'l': case 'L': pstack.data[++pstack.sp] = lpoint; break; case 'p': case 'P': pstack.data[++pstack.sp] = Pc; break; default: addr = rest; rest = split(rest); value = get_hex_number(addr); if (value == -1L) printf("push [l|p|]\n"); else pstack.data[++pstack.sp]=(unsigned short)value; break; } return(OK); } clb(junk) char *junk; { B = 0; return(DISPLAY); } seb(junk) char *junk; { B = 1; return(DISPLAY); } clc(junk) char *junk; { C = 0; return(DISPLAY); } sec(junk) char *junk; { C = 1; return(DISPLAY); } sev(junk) char *junk; { V = 1; return(DISPLAY); } clv(junk) char *junk; { V = 0; return(DISPLAY); } sed(junk) char *junk; { D = 1; return(DISPLAY); } cld(junk) char *junk; { D = 0; return(DISPLAY); } sei(junk) char *junk; { I = 1; return(DISPLAY); } clri(junk) char *junk; { I = 0; return(DISPLAY); } sen(junk) char *junk; { N = 1; return(DISPLAY); } cln(junk) char *junk; { N = 0; return(DISPLAY); } sez(junk) char *junk; { NZ = 0; return(DISPLAY); } clz(junk) char *junk; { NZ = 1; return(DISPLAY); } quit_emulator(junk) char *junk; { exit(0); } ver(junk) char *junk; { printf("a2 - Apple II emulator (c) Copyright 1990 by Rich Skrenta & Tom Markson\n"); return(OK); } refresh(junk) char *junk; { in_cli = FALSE; return(OK); } shell_escape(rest) char *rest; { char line[100]; char *s; s = getenv("SHELL"); if (s == NULL) s = "/bin/sh"; strcpy(line, s); if (*rest != '\0') { strcat(line, " -c '"); strcat(line, rest); strcat(line, "'"); } system(line); printf("\n"); return(OK); } do_soft_reset(rest) char *rest; { Pc = mem[0xFFFC] | (mem[0xFFFD] << 8); return(DISPLAY); } do_bload(rest) char *rest; { char *first; char *file; unsigned short start; long foo; file = rest; rest = split(rest); first = rest; rest = split(rest); foo = get_hex_number(first); if (foo == -1) { printf("usage: bload file hex-address\n"); return(OK); } start = (unsigned int) foo; bload(file, start); return(OK); } do_bsave(rest) char *rest; { char *startc, *sizec, *file; unsigned short start, size; long istart, iend; file = rest; rest = split(rest); startc = rest; rest = split(rest); sizec = rest; rest = split(rest); istart = get_hex_number(startc); iend = get_hex_number(sizec); if ((istart == -1) || (iend == -1)) printf("usage: bsave file hex-address hex-length\n"); else { start = (unsigned short) istart; size = (unsigned short) iend; bsave(file, start, size); } return(OK); } show_point(rest) char *rest; { lpoint = Pc; return(DISPLAY); } hack(rest) char *rest; { extern int cur_track; cur_track = get_hex_number(rest); return(OK); } do_jump(rest) char *rest; { char *start; long istart; start = rest; rest = split(rest); istart = get_hex_number(start); if (istart == -1) { printf("usage: jmp \n"); return(OK); } else { Pc = istart & 0xFFFF; return(DISPLAY); } } trace(rest) char *rest; { char *addr1, *addr2, *file; long addr1i, addr2i; addr1 = rest; rest = split(rest); addr2 = rest; rest = split(rest); file = rest; rest = split(rest); addr1i = get_hex_number(addr1); addr2i = get_hex_number(addr2); if (addr1i == -1 && addr2i == -1) { if (trace_lo == -1) printf("No trace region set\n"); else printf("Tracing between $%.4X and $%.4x\n", trace_lo, trace_hi); return(OK); } if (addr1i == -1 || addr2i == -1) { printf("usage: trace [low high]\n"); return(OK); } if (logging_fp == NULL) { if (*file == '\0' || file == NULL) { printf("Trace log will go to file 'trace'.\n"); file = "trace"; } logging_fp = fopen(file, "w"); if (logging_fp == NULL) { perror("can't open trace file"); trace_lo = -1; return(OK); } } trace_lo = addr1i & 0xFFFF; trace_hi = addr2i & 0xFFFF; return(OK); } ldx(rest) char *rest; { long number; char *first; first = rest; rest = split(rest); number = get_hex_number(first); number &= 0xFF; if (number < 0) { printf("usage: ldx \n"); return(OK); } X = number & 0xFF; return(DISPLAY); } ldy(rest) char *rest; { long number; char *first; first = rest; rest = split(rest); number = get_hex_number(first); if (number < 0) { printf("usage: ldy \n"); return(OK); } Y = number & 0xFF; return(DISPLAY); } lda(rest) char *rest; { long number; char *first; first = rest; rest = split(rest); number = get_hex_number(first); if (number < 0) { printf("usage: lda \n"); return(OK); } A = number & 0xFF; return(DISPLAY); } lds(rest) char *rest; { long number; char *first; first = rest; rest = split(rest); number = get_hex_number(first); if (number < 0) { printf("usage: lds \n"); return(OK); } Sp = number & 0xFF; return(DISPLAY); } set_break_point(rest) char *rest; { long addr; char *first; first = rest; rest = split(rest); addr = get_hex_number(first); if (addr == -1) if (breakpoint == -1) printf("no breakpoint set\n"); else printf("break point set at %x\n", (unsigned short)breakpoint); else breakpoint = addr; running = FALSE; return(OK); } clear_break_point(rest) char *rest; { breakpoint = -1; return(OK); } notrace(junk) char *junk; { trace_lo = -1; if (logging_fp == NULL) return(OK); else fclose(logging_fp); logging_fp = NULL; return(OK); } insert_disk(rest) char *rest; { char *name; char *which; int fd; int read_only = 0; name = rest; rest = split(rest); which = rest; rest = split(rest); if (name == NULL || *name == '\0') { printf("usage: insert [drive]\n"); return(OK); } fd = open(name, 2); /* attempt open for read/write */ if (fd >= 0) read_only = 0; else { /* attempt open read only */ read_only = 1; fd = open(name, 0); } if (fd < 0) { fprintf(stderr, "can't open %s: ", name); perror(""); return(OK); } if (*which == '2') drive = 1; else drive = 0; if (disk[drive] >= 0) close(disk[drive]); strcpy(diskname[drive], name); disk[drive] = fd; write_prot[drive] = read_only; printf("disk %d inserted, %swrite protected\n", drive + 1, read_only ? "" : "not "); return(OK); } dissassemble(rest) char *rest; { unsigned short start,end; long istart; long iend; int count = 0; char *first,*last; first = rest; rest = split(rest); last = rest; rest = split(rest); istart = get_hex_number(first); iend = get_hex_number(last); if (istart != -1) lpoint = istart; if (iend == -1) iend=65537; while ( (long) lpoint < iend) { lpoint += diss(lpoint, stdout); printf("\n"); count++; if (iend == 65537) if (count > term_lines-3) break; } return OK; } ascii_dump(l,h) unsigned short l,h; { while (l < h) { if (isprint(mem[l])) printf("%c",mem[l]); else printf("."); l++; } } hex_dump(rest) char *rest; { char *start,*end; unsigned short last, addr,oaddr; long iaddr1,iaddr2; int count; start = rest; rest = split(rest); end = rest; rest = split(rest); iaddr1 = get_hex_number( start ); iaddr2 = get_hex_number( end ); if (iaddr2 != -1 && iaddr1 > iaddr2) return(OK); if (iaddr1 != -1) lpoint = (unsigned short) iaddr1; if (iaddr2 == -1) last = lpoint + 1; else last = (unsigned short) iaddr2 + 1; last &= 0xFFFF; addr = lpoint; count = 0; printf("%.4X: ", addr); oaddr = addr; do { if (count % 16 == 0 && count != 0) { ascii_dump(oaddr,addr); oaddr = addr; printf("\n%.4X: ", addr); } printf("%.2X ", mem[addr]); addr++; count++; } while (addr != last); while ((count % 16) != 0) { printf(" "); /* 3 spaces dd_ */ count++; } ascii_dump(oaddr,addr); printf("\n"); return(OK); } deposit(rest) char *rest; { char *addr; char *value; unsigned short location; long iloc; unsigned char val; int fired_once; addr = rest; rest = split(rest); fired_once = 0; iloc = get_hex_number(addr); if (iloc == -1) { printf("usage: deposit [...]\n"); return(OK); } location = (unsigned short) iloc; do { value = rest; rest = split(rest); val = get_hex_number(value); if (val == -1) { if (!fired_once) printf("Invalid or Missing Hex address\n"); return OK; } mem[location++] = val; fired_once = 1; } while (*rest != '\0'); return(OK); } phantom_trace(rest) char *rest; { char *phantoms; char *addr1s; char *addr2s; char *file; long phantom; long low_val,high_val; int err = 0; phantoms = rest; rest = split(rest); addr1s = rest; rest = split(rest); addr2s = rest; rest = split(rest); file = rest; rest = split(rest); phantom = (unsigned short)get_hex_number(phantoms); low_val = get_hex_number(addr1s); high_val = get_hex_number(addr2s); if (*phantoms == '\0') { if (phantom_location == -1) { printf("The phantom sleeps."); if (trace_lo != -1 && trace_hi != -1) printf("however, a trace is active."); printf("\n"); } else printf("the phantom waits until Pc = %.4X and then traces from %.4X to %.4X\n",phantom_location,trace_lo,trace_hi); return(OK); } if (low_val == -1 || high_val == -1 || phantom == -1) { printf("usage: phantom [file]\n"); return OK; } phantom_location = phantom; trace_lo = low_val; trace_hi = high_val; if (logging_fp == NULL) { if (*file == '\0' || file == NULL) { printf("the phantom will trace to file 'trace'.\n"); file = "trace"; } logging_fp = fopen(file, "w"); if (logging_fp == NULL) { perror("can't open trace file"); trace_lo = -1; return(OK); } } return OK; } no_phantom_trace(rest) char *rest; { phantom_location = -1; trace_lo = -1; printf("the phantom goes to sleep.\n"); if (logging_fp == NULL) return OK; fclose(logging_fp); logging_fp = NULL; return OK; } cd(rest) char *rest; { char *first; char path[200]; first = rest; rest = split(rest); if (*first != '\0') { if (chdir(first)) { perror("cd"); printf("CWD remains "); } } printf("%s\n",getcwd(path,198)); return OK; } map(rest) char *rest; { map_to_upper = !map_to_upper; printf("Uppercase Mapping is %s\n",(map_to_upper)?"On":"Off"); return OK; } sex(rest) char *rest; { printf("You'll need a real Apple for that sort of thing\n"); return OK; } help(rest) char *rest; { printf("![command] Escape to Unix\n"); printf(". Display Current Pc Point\n"); printf("bload file addr load binary file into mem at addr\n"); printf("breakpoint [addr] Set the Breakpoint to addr\n"); printf("bsave file start end Save Memory from start to end in file\n"); printf("cd [directory] Set/Show Current Working Directory\n"); printf("cl[cdinvz] Clear appropriate Status Bit\n"); printf("continue Resume Execution of Emulator\n"); printf("deposit addr [val]+ Put val(s) into addr\n"); printf("dup [l|p] duplicate top of stack into l or p\n"); printf("escape char set escape char to be char \n"); printf("examine addr Display Value in addr\n"); printf("insert file drive# Make file disk in drive#\n"); printf("jmp addr Make Pc=addr\n"); printf("ld[asxy] val Load Register with val\n"); printf("list [addr] [addr] Dissassemble at point or addr\n"); printf("map Toggle lower -> upper case mapping\n"); printf("nobreak Turn off breakpoint\n"); printf("pop [l|p] get p or l from top of stack\n"); printf("push [l|p| push l,p, or hex addr on stack\n"); printf("reset Pc = Apple Reset Vector\n"); printf("se[cdinvz] Set appropriate Status Flag\n"); printf("trace [addr] [addr] Trace Between addresses/display trace point\n"); return OK; } set_escape_char(rest) char *rest; { char c; if (*rest != '\0') escape_char = *rest; printf("escape character is "); if (isprint(escape_char)) printf("%c",(int)escape_char); else printf("^%c",(char)escape_char+64); printf(" (0x%.2X)",(int)escape_char); printf("\n"); return(OK); } disk_names(rest) char *rest; { printf("drive 1: %s\n", disk[0] >= 0 ? diskname[0] : "empty"); printf("drive 2: %s\n", disk[1] >= 0 ? diskname[1] : "empty"); return(OK); } @EOF chmod 644 commands.c echo x - dos.c cat >dos.c <<'@EOF' /* * 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 #include "a2.h" char *rwts_func[] = {"-s", "", "-w", "-?", "-f"}; rwts() { char s[50]; unsigned short iob; unsigned short buf; int track; int sector; int cmd; char zero_buf[256]; int i; mem[0x48] = Y; mem[0x49] = A; mem[0x6F8] = 2; mem[0x4F8] = 4; iob = join(Y, A); track = mem[iob + 4]; sector = mem[iob + 5]; buf = join(mem[iob + 8], mem[iob + 9]); cmd = mem[iob + 12]; if (cmd > 4) cmd = 3; /* unknown command */ if (mem[iob + 2] == 2) drive = 1; else drive = 0; if ((cmd == 2 || cmd == 4) && write_prot[drive]) { C = 1; mem[iob + 13] = 0x10; /* Write protected */ DO_RTS; return; } if (mem[iob] != 1 || disk[drive] < 0 || track > 35 || sector > 15 || cmd == 3 || buf > 0xFE00) { C = 1; mem[iob + 13] = 0x40; /* IO Error */ DO_RTS; return; } sprintf(s, "rwts%s t=%d s=%d%s", rwts_func[cmd], track, sector, drive ? " d2" : ""); info(s); switch (cmd) { case 0: /* seek */ break; case 1: /* read */ read_disk(track, sector, &mem[buf]); break; case 2: /* write */ write_disk(track, sector, &mem[buf]); break; case 4: /* format */ for (i = 0; i < 256; i++) zero_buf[i] = 0; for (track = 0; track < 35; track++) for (sector = 0; sector < 16; sector++) write_disk(track, sector, zero_buf); break; } C = 0; A = 0; DO_RTS; } @EOF chmod 644 dos.c echo x - hex.c cat >hex.c <<'@EOF' /* * Turn an Apple II monitor ROM hex dump back into binary data * usage: hex < hex_data > bin_data */ #include main() { char buf[100]; int i, j; int addr; int m[8]; unsigned char c; while (fgets(buf, 100, stdin) != NULL) { i = sscanf(buf, "%x- %x %x %x %x %x %x %x %x", &addr, &m[0], &m[1], &m[2], &m[3], &m[4], &m[5], &m[6], &m[7]); for (j = 1; j < i; j++) { c = m[j - 1]; write(1, &c, 1); } } } @EOF chmod 644 hex.c echo x - jump.c cat >jump.c <<'@EOF' /* * 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 #include #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 intented 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; } } @EOF chmod 644 jump.c echo x - main.c cat >main.c <<'@EOF' /* * 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 #include #include #include "a2.h" int save_flags; /* terminal flags */ char escape_char = '~'; unsigned short Pc; unsigned char Sp = 0xFF; /* stack pointer */ unsigned int A = 0; /* accumulator */ unsigned char X = 0; /* X register */ unsigned char Y = 0; /* Y register */ unsigned int N = 0; /* 7 - sign */ unsigned int V = 0; /* 6 - Overflow */ /* 5 - Unused */ unsigned int B = 1; /* 4 - Break */ unsigned int D = 0; /* 3 - Decimal */ unsigned int I = 0; /* 2 - Interrupt */ unsigned int NZ = 1; /* 1 - Zero */ unsigned int C = 0; /* 0 - Carry */ int term_lines, term_cols; int running = TRUE; int tracing = FALSE; int disk[] = {-1, -1}; int write_prot[2]; int drive = 0; main(argc, argv) int argc; char **argv; { int c; int errflag = 0; char *f8rom, *d0rom; int cli_first = FALSE; safety_check(); f8rom = "AUTOSTART.ROM"; d0rom = "APPLESOFT.ROM"; while ((c = getopt(argc, argv, "cim")) != -1) { switch (c) { case 'c': cli_first = TRUE; break; case 'i': d0rom = "INTEGER.ROM"; break; case 'm': f8rom = "MONITOR.ROM"; break; case '?': default: errflag++; } } if (errflag) { fprintf(stderr, "usage: %s\n", argv[0]); fprintf(stderr, "\t-m\tLoad MONITOR.ROM instead of AUTOSTART.ROM at $F800\n"); fprintf(stderr, "\t-i\tLoad INTEGER.ROM instead of APPLESOFT.ROM at $D000\n"); fprintf(stderr, "\t-c\tEnter command mode before executing any instructions\n"); exit(1); } printf("a2 -- Apple II emulator. Escape character is %c\n", escape_char); if (!bload(f8rom, 0xF800)) exit(1); bload(d0rom, 0xD000); bload("DISK.PROM", 0xC600); if (!InitScreen()) exit(1); ScreenSize(&term_lines, &term_cols); memory_setup(); set_special_jumps(); Pc = join(mem[0xFFFC], mem[0xFFFD]); if (cli_first) cli(); else ClearScreen(); while (1) { set_term(); run(); cli(); } } restore_term() { /* SetNormal(); /* Turn off inverse video */ Raw(FALSE); fcntl(0, F_SETFL, save_flags); signal(SIGINT, SIG_DFL); } set_term() { int catch_intr(); int cleanup(); signal(SIGINT, catch_intr); signal(SIGQUIT, cleanup); signal(SIGTERM, cleanup); save_flags = fcntl(0, F_GETFL, 0); Raw(TRUE); } cleanup() { restore_term(); exit(0); } catch_intr() { signal(SIGINT, catch_intr); running = FALSE; tracing = FALSE; } bload(fnam, addr) char *fnam; unsigned short addr; { int fd; long len; fd = open(fnam, O_RDONLY); if (fd < 0) { fprintf(stderr, "can't open %s: ", fnam); perror(""); return(FALSE); } len = 65536 - addr; if (len == 65536) { /* stupid $%!*&#~ 16 bit systems */ if (read(fd, &mem[addr], 4096) < 0) { fprintf(stderr, "bad read of %s: ", fnam); perror(""); return(FALSE); } addr += 4096; len -= 4096; } if (read(fd, &mem[addr], len) < 0) { fprintf(stderr, "bad read of %s: ", fnam); perror(""); return(FALSE); } close(fd); return(TRUE); } bsave(fnam, addr, size) char *fnam; unsigned short addr,size; { int fd; unsigned sizel; int x; sizel=size; if (sizel==0) sizel=65535; fd=open(fnam,O_WRONLY|O_CREAT,0644); if (fd < 0) { printf("can't open %s: ", fnam); perror(""); return; } x=write(fd,&mem[addr],sizel); if (size == 0) x=write(fd,&mem[65535],1); if (x==-1) perror("write"); close(fd); } /* * I make certain assumptions about rollover so that I can do * things like X++ and know that if X is 0xFF it will rollover * to 0x00. If I didn't know this I'd have to do X = (X+1) & 0xFF * If your machine assert fails on the code below you'll have to * rewrite the code that depends on rollover */ safety_check() { unsigned char c; unsigned short s; c = 0xFF; assert(++c == 0x00); assert(--c == 0xFF); s = 0xFFFF; assert(++s == 0x0000); assert(--s == 0xFFFF); } asfail(file, line, cond) char *file; int line; char *cond; { fprintf(stderr, "assertion failure: %s (%d): %s\n", file, line, cond); restore_term(); abort(); exit(1); } @EOF chmod 644 main.c echo x - mapper.c cat >mapper.c <<'@EOF' #include /* * Map a disk image in Prodos block ordering to DOS 3.3 block ordering * usage: mapper < old_image > new_image */ main() { unsigned char buf[4096]; int track; for (track = 0; track < 35; track++) { if (read(0, buf, 4096) != 4096) { perror("bad read"); exit(1); } write(1, buf, 256); write(1, &buf[0xE00], 256); write(1, &buf[0xD00], 256); write(1, &buf[0xC00], 256); write(1, &buf[0xB00], 256); write(1, &buf[0xA00], 256); write(1, &buf[0x900], 256); write(1, &buf[0x800], 256); write(1, &buf[0x700], 256); write(1, &buf[0x600], 256); write(1, &buf[0x500], 256); write(1, &buf[0x400], 256); write(1, &buf[0x300], 256); write(1, &buf[0x200], 256); write(1, &buf[0x100], 256); write(1, &buf[0xF00], 256); } } @EOF chmod 644 mapper.c echo x - mem.c cat >mem.c <<'@EOF' /* * 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 #include "a2.h" unsigned char mem[65536]; /* 64K memory image */ unsigned char jmp_tbl[65536]; /* jmp & jsr interceptor functions */ int (*mem_set[256])(); /* memory store interceptors */ unsigned char rom[0x3000]; unsigned char ram[0x2000]; unsigned char bank1[0x1000]; unsigned char bank2[0x1000]; int ram_read = 0; int ram_write = 0; int bank2_enable = 0; memory_setup() { long i; int set_writep(); for (i = 0; i < 256; i++) mem_set[i] = NULL; for (i = 0; i < 65536; i++) jmp_tbl[i] = 0; writep(set_writep); ram_copy(&mem[0xD000], rom, 0x3000); } ram_copy(from, to, len) unsigned char *from; unsigned char *to; int len; { while (len--) *to++ = *from++; } /* * Write protect/unprotect D000-FFFF */ writep(fn) int (*fn)(); { int i; for (i = 0xD0; i <= 0xFF; i++) mem_set[i] = fn; } set_writep(a, n) unsigned short a; unsigned char n; { /* Just eat it. */ } set_ramwrite(a, n) unsigned short a; unsigned char n; { if (a >= 0xE000) ram[a - 0xE000] = n; else if (bank2_enable) bank2[a - 0xD000] = n; else bank1[a - 0xD000] = n; } ram_card(addr) unsigned short addr; { if (ram_read) { ram_copy(&mem[0xE000], ram, 0x2000); if (bank2_enable) ram_copy(&mem[0xD000], bank2, 0x1000); else ram_copy(&mem[0xD000], bank1, 0x1000); } switch (addr & 0x000F) { case 0x00: /* C080 */ ram_read = 1; ram_write = 0; bank2_enable = 1; ram_copy(ram, &mem[0xE000], 0x2000); ram_copy(bank2, &mem[0xD000], 0x1000); writep(set_writep); break; case 0x01: /* C081 */ ram_read = 0; ram_write = 1; bank2_enable = 1; ram_copy(rom, &mem[0xD000], 0x3000); writep(set_ramwrite); break; case 0x02: /* C082 */ ram_read = 0; ram_write = 0; bank2_enable = 1; ram_copy(rom, &mem[0xD000], 0x3000); writep(set_writep); break; case 0x03: /* C083 */ ram_read = 1; ram_write = 1; bank2_enable = 1; ram_copy(ram, &mem[0xE000], 0x2000); ram_copy(bank2, &mem[0xD000], 0x1000); writep(NULL); break; case 0x08: /* C088 */ ram_read = 1; ram_write = 0; bank2_enable = 0; ram_copy(ram, &mem[0xE000], 0x2000); ram_copy(bank1, &mem[0xD000], 0x1000); writep(set_writep); break; case 0x09: /* C089 */ ram_read = 0; ram_write = 1; bank2_enable = 0; ram_copy(rom, &mem[0xD000], 0x3000); writep(set_ramwrite); break; case 0x0a: /* C08A */ ram_read = 0; ram_write = 0; bank2_enable = 0; ram_copy(rom, &mem[0xD000], 0x3000); writep(set_writep); break; case 0x0b: /* C08B */ ram_read = 1; ram_write = 1; bank2_enable = 0; ram_copy(ram, &mem[0xE000], 0x2000); ram_copy(bank1, &mem[0xD000], 0x1000); writep(NULL); break; } } @EOF chmod 644 mem.c echo x - parse.c cat >parse.c <<'@EOF' /* * 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 #include #include #include "a2.h" #include "cli.h" char * split(s) char *s; { char *t; extern char *strchr(); assert(s != NULL); t = strchr(s, ' '); if (t == NULL) return(""); assert(*t == ' '); *t++ = '\0'; while (*t && *t == ' ') t++; return(t); } match(a, b) char *a; char *b; { assert(a != NULL); assert(b != NULL); if (*b == '.' && strlen(b) > 1) b++; while (*a && *b) { if (toupper(*a) != toupper(*b)) return(NO_MATCH); a++; b++; } if (!*a) { if (!*b) return(IDENTICAL); else return(PARTIAL); } else return(NO_MATCH); } is_hex_number(s) char *s; { char *temp; temp = s; assert(s != NULL); while (*s) if (!isxdigit(*s++)) return(FALSE); if (temp != s) return TRUE; else return FALSE; } long get_hex_number(s) char *s; { unsigned int x; if (is_hex_number(s)) sscanf(s, "%x", &x); else return(-1); return( (long) x ); } parse_str(tbl, s, t) struct cmdtbl tbl[]; char *s; char *t; /* to be passed to handler functions */ { int i; int ret; int partial = -1; int count = 0; i = 0; while (tbl[i].name != NULL) { ret = match(s, tbl[i].name); if (ret == IDENTICAL) { partial = i; count = 0; break; } else if (ret == PARTIAL) { partial = i; count++; } i++; } if (partial == -1) return(NO_MATCH); if (count > 1) return(AMBIGUOUS); if (tbl[partial].func == NULL) return(NOT_IMPLEMENTED); assert(t != NULL); return (*tbl[partial].func)(t); } parse(tbl, s) struct cmdtbl tbl[]; char *s; { int ret; char buf[1024]; char *t; if (*s == '!') { /* shell escape-ish thing */ shell_escape(++s); return(FALSE); } t = split(s); if (*s == '\0') { return(TRUE); /* single step */ } else if (strcmp(s, "?") == 0) { dump_list(tbl, "Command, one of the following:\n\n"); } else switch (parse_str(tbl, s, t)) { case AMBIGUOUS: printf("Ambiguous command '%s'.\n", s); break; case NO_MATCH: printf("Unknown command. Type ? for a list.\n"); break; case NOT_IMPLEMENTED: printf("Sorry, command not implemented yet.\n"); break; case OK: break; case DISPLAY: status(stdout); break; default: assert(FALSE); } return(FALSE); } dump_list(tbl, header) struct cmdtbl tbl[]; char *header; { int i, count; char buf[1024]; printf(header); i = 0; count = 0; while (tbl[i].name != NULL) { if (*tbl[i].name != '.' || strlen(tbl[i].name) == 1) { if (count % 4 == 3) printf(" %-15s\n", tbl[i].name); else printf(" %-15s", tbl[i].name); count++; } i++; } if (count % 4 != 0) printf("\n"); } @EOF chmod 644 parse.c echo x - prodos.c cat >prodos.c <<'@EOF' /* * 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 #include "a2.h" #define BSIZE 512 /* block size */ #define D1SIZE 280 /* Size of disk 1 */ #define D2SIZE 1024 /* Size of disk 2 */ /* * Prodos to DOS 3.3 block mapping */ int conv1[] = { 0x00, 0x0D, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01 }; int conv2[] = { 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x0F }; proformat() { if (write_prot[drive]) { C = 1; A = 0x2B; /* Write protected */ return; } C = 0; A = 0; } proread() { int block; unsigned short ptr; int track, sector; char s[50]; block = join(mem[0x46], mem[0x47]); ptr = join(mem[0x44], mem[0x45]); sprintf(s, "proread b=%d", block); info(s); track = block / 8; sector = conv1[block % 8]; read_disk(track, sector, &mem[ptr]); ptr += 0x100; sector = conv2[block % 8]; read_disk(track, sector, &mem[ptr]); C = 0; A = 0; } prowrite() { int block; unsigned short ptr; int track; int sector; char s[50]; if (write_prot[drive]) { C = 1; A = 0x2B; /* Write protected */ return; } block = join(mem[0x46], mem[0x47]); ptr = join(mem[0x44], mem[0x45]); sprintf(s, "prowrite b=%d", block); info(s); track = block / 8; sector = conv1[block % 8]; write_disk(track, sector, &mem[ptr]); ptr += 0x100; sector = conv2[block % 8]; write_disk(track, sector, &mem[ptr]); C = 0; A = 0; } prostatus() { C = 0; A = 0; Y = high(D1SIZE); X = low(D1SIZE); } prodos() { if (mem[0x43] < 0x80) drive = 0; else drive = 1; if (disk[drive] < 0) { C = 1; A = 0x27; /* IO Error */ } else switch (mem[0x42]) { case 0: prostatus(); break; case 1: proread(); break; case 2: prowrite(); break; case 3: proformat(); break; } DO_RTS; } @EOF chmod 644 prodos.c echo x - screen.c cat >screen.c <<'@EOF' /* * 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 #include "a2.h" extern char screen_map[]; /* at the bottom of this file */ extern int text1[]; int line1[0x400]; int col1[0x400]; info(s) char *s; { MoveCursor(0, 57); printf("%-20s", s); last_line = -1; last_col = -1; fflush(stdout); } screen_setup() { extern int set_text1f(); int line, col; int addr, base; int i; for (i = 0; i < 0x400; i++) { line1[i] = -1; col1[i] = -1; } mem_set[0x04] = set_text1f; mem_set[0x05] = set_text1f; mem_set[0x06] = set_text1f; mem_set[0x07] = set_text1f; for (line = 0; line < 24; line++) { base = text1[line]; for (col = 0; col < 40; col++) { addr = base + col; mem[addr] = 0xA0; line1[addr - 0x400] = line; col1[addr - 0x400] = col; } } } int last_line = -1; int last_col = -1; #define appleout(n) if (n >= 0x80) putchar(screen_map[n]); else { StartInverse(); putchar(screen_map[n]); EndInverse(); } set_text1f(addr, n) unsigned short addr; unsigned char n; { int line, col; unsigned char c; if (mem[addr] == n) /* no change, don't do anything */ return; mem[addr] = n; line = line1[addr - 0x400]; col = col1[addr - 0x400]; if (line == -1) return; /* * Stuff to try to make updating more efficient * Is it really worth it? */ if (line == last_line) { if (col == 0) putchar('\r'); else switch (col - last_col) { case 4: c = mem[addr - 3]; appleout(c); c = mem[addr - 2]; appleout(c); c = mem[addr - 1]; appleout(c); break; case 3: c = mem[addr - 2]; appleout(c); c = mem[addr - 1]; appleout(c); break; case 2: c = mem[addr - 1]; appleout(c); break; case 1: /* already there */ break; case 0: putchar('\b'); break; case -1: putchar('\b'); putchar('\b'); break; case -2: putchar('\b'); putchar('\b'); putchar('\b'); break; case -3: putchar('\b'); putchar('\b'); putchar('\b'); putchar('\b'); break; default: MoveCursor(line, col); } } else MoveCursor(line, col); appleout(n); fflush(stdout); last_line = line; last_col = col; } set_text1(addr, n) unsigned short addr; unsigned char n; { int line, col; unsigned char c; if (mem[addr] == n) /* no change, don't do anything */ return; mem[addr] = n; line = line1[addr - 0x400]; col = col1[addr - 0x400]; if (line == -1) return; /* * Stuff to try to make updating more efficient * Is it really worth it? */ if (line == last_line) { if (col == 0) putchar('\r'); else switch (col - last_col) { case 4: c = mem[addr - 3]; appleout(c); c = mem[addr - 2]; appleout(c); c = mem[addr - 1]; appleout(c); break; case 3: c = mem[addr - 2]; appleout(c); c = mem[addr - 1]; appleout(c); break; case 2: c = mem[addr - 1]; appleout(c); break; case 1: /* already there */ break; case 0: putchar('\b'); break; case -1: putchar('\b'); putchar('\b'); break; case -2: putchar('\b'); putchar('\b'); putchar('\b'); break; case -3: putchar('\b'); putchar('\b'); putchar('\b'); putchar('\b'); break; default: MoveCursor(line, col); } } else MoveCursor(line, col); appleout(n); last_line = line; last_col = col; } redraw_screen() { int i, j; unsigned short base; unsigned char c; ClearScreen(); for (i = 0; i < 24; i++) { base = text1[i]; for (j = 0; j < 40; j++) { c = mem[base + j]; appleout(c); } if (i < 23) putchar('\n'); } last_line = -1; last_col = -1; fflush(stdout); } /* * Screen display mapping table */ char screen_map[] = { '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* $00 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* $08 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* $10 */ 'X', 'Y', 'Z', '[', '\\',']', '^', '_', /* $18 */ ' ', '!', '"', '#', '$', '%', '&', '\'', /* $20 */ '(', ')', '*', '+', ',', '-', '.', '/', /* $28 */ '0', '1', '2', '3', '4', '5', '6', '7', /* $30 */ '8', '9', ':', ';', '<', '=', '>', '?', /* $38 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* $40 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* $48 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* $50 */ 'X', 'Y', 'Z', '[', '\\',']', '^', '_', /* $58 */ ' ', '!', '"', '#', '$', '%', '&', '\'', /* $60 */ '(', ')', '*', '+', ',', '-', '.', '/', /* $68 */ '0', '1', '2', '3', '4', '5', '6', '7', /* $70 */ '8', '9', ':', ';', '<', '=', '>', '?', /* $78 */ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* $80 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* $88 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* $90 */ 'x', 'y', 'z', '[', '\\',']', '^', '_', /* $98 */ ' ', '!', '"', '#', '$', '%', '&', '\'', /* $A0 */ '(', ')', '*', '+', ',', '-', '.', '/', /* $A8 */ '0', '1', '2', '3', '4', '5', '6', '7', /* $B0 */ '8', '9', ':', ';', '<', '=', '>', '?', /* $B8 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* $C0 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* $C8 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* $D0 */ 'X', 'Y', 'Z', '[', '\\',']', '^', '_', /* $D8 */ ' ', '!', '"', '#', '$', '%', '&', '\'', /* $E0 */ '(', ')', '*', '+', ',', '-', '.', '/', /* $E8 */ '0', '1', '2', '3', '4', '5', '6', '7', /* $F0 */ '8', '9', ':', ';', '<', '=', '>', '?', /* $F8 */ }; int text1[] = { 0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780, 0x428, 0x4A8, 0x528, 0x5A8, 0x628, 0x6A8, 0x728, 0x7A8, 0x450, 0x4D0, 0x550, 0x5D0, 0x650, 0x6D0, 0x750, 0x7D0, 0x478, 0x4F8, 0x578, 0x5F8, 0x678, 0x6F8, 0x778, 0x7F8 }; @EOF chmod 644 screen.c echo x - table.c cat >table.c <<'@EOF' /* * 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 #include "a2.h" struct op_info opcode[] = { {"brk", M_NONE}, /* 0x0 */ {"ora", M_INDX}, /* 0x1 */ {"", M_NONE}, /* 0x2 */ {"", M_NONE}, /* 0x3 */ {"tsb", M_ZP}, /* 0x4 */ /* 65C02 */ {"ora", M_ZP}, /* 0x5 */ {"asl", M_ZP}, /* 0x6 */ {"", M_NONE}, /* 0x7 */ {"php", M_NONE}, /* 0x8 */ {"ora", M_IMM}, /* 0x9 */ {"asl", M_NONE}, /* 0xa */ {"", M_NONE}, /* 0xb */ {"tsb", M_ABS}, /* 0xc */ /* 65C02 */ {"ora", M_ABS}, /* 0xd */ {"asl", M_ABS}, /* 0xe */ {"", M_NONE}, /* 0xf */ {"bpl", M_REL}, /* 0x10 */ {"ora", M_INDY}, /* 0x11 */ {"ora", M_ZIND}, /* 0x12 */ /* 65C02 */ {"", M_NONE}, /* 0x13 */ {"trb", M_ZP}, /* 0x14 */ /* 65C02 */ {"ora", M_ZPX}, /* 0x15 */ {"asl", M_ZPX}, /* 0x16 */ {"", M_NONE}, /* 0x17 */ {"clc", M_NONE}, /* 0x18 */ {"ora", M_ABSY}, /* 0x19 */ {"ina", M_NONE}, /* 0x1a */ /* 65C02 */ {"", M_NONE}, /* 0x1b */ {"trb", M_ABS}, /* 0x1c */ /* 65C02 */ {"ora", M_ABSX}, /* 0x1d */ {"asl", M_ABSX}, /* 0x1e */ {"", M_NONE}, /* 0x1f */ {"jsr", M_ABS}, /* 0x20 */ {"and", M_INDX}, /* 0x21 */ {"", M_NONE}, /* 0x22 */ {"", M_NONE}, /* 0x23 */ {"bit", M_ZP}, /* 0x24 */ {"and", M_ZP}, /* 0x25 */ {"rol", M_ZP}, /* 0x26 */ {"", M_NONE}, /* 0x27 */ {"plp", M_NONE}, /* 0x28 */ {"and", M_IMM}, /* 0x29 */ {"rol", M_NONE}, /* 0x2a */ {"", M_NONE}, /* 0x2b */ {"bit", M_ABS}, /* 0x2c */ {"and", M_ABS}, /* 0x2d */ {"rol", M_ABS}, /* 0x2e */ {"", M_NONE}, /* 0x2f */ {"bmi", M_REL}, /* 0x30 */ {"and", M_INDY}, /* 0x31 */ {"and", M_ZIND}, /* 0x32 */ /* 65C02 */ {"", M_NONE}, /* 0x33 */ {"bit", M_ZPX}, /* 0x34 */ /* 65C02 */ {"and", M_ZPX}, /* 0x35 */ {"rol", M_ZPX}, /* 0x36 */ {"", M_NONE}, /* 0x37 */ {"sec", M_NONE}, /* 0x38 */ {"and", M_ABSY}, /* 0x39 */ {"dey", M_NONE}, /* 0x3a */ /* 65C02 */ {"", M_NONE}, /* 0x3b */ {"bit", M_ABSX}, /* 0x3c */ /* 65C02 */ {"and", M_ABSX}, /* 0x3d */ {"rol", M_ABSX}, /* 0x3e */ {"", M_NONE}, /* 0x3f */ {"rti", M_NONE}, /* 0x40 */ {"eor", M_INDX}, /* 0x41 */ {"", M_NONE}, /* 0x42 */ {"", M_NONE}, /* 0x43 */ {"", M_NONE}, /* 0x44 */ {"eor", M_ZP}, /* 0x45 */ {"lsr", M_ZP}, /* 0x46 */ {"", M_NONE}, /* 0x47 */ {"pha", M_NONE}, /* 0x48 */ {"eor", M_IMM}, /* 0x49 */ {"lsr", M_NONE}, /* 0x4a */ {"", M_NONE}, /* 0x4b */ {"jmp", M_ABS}, /* 0x4c */ {"eor", M_ABS}, /* 0x4d */ {"lsr", M_ABS}, /* 0x4e */ {"", M_NONE}, /* 0x4f */ {"bvc", M_REL}, /* 0x50 */ {"eor", M_INDY}, /* 0x51 */ {"eor", M_ZIND}, /* 0x52 */ /* 65C02 */ {"", M_NONE}, /* 0x53 */ {"", M_NONE}, /* 0x54 */ {"eor", M_ZPX}, /* 0x55 */ {"lsr", M_ZPX}, /* 0x56 */ {"", M_NONE}, /* 0x57 */ {"cli", M_NONE}, /* 0x58 */ {"eor", M_ABSY}, /* 0x59 */ {"phy", M_NONE}, /* 0x5a */ /* 65C02 */ {"", M_NONE}, /* 0x5b */ {"", M_NONE}, /* 0x5c */ {"eor", M_ABSX}, /* 0x5d */ {"lsr", M_ABSX}, /* 0x5e */ {"", M_NONE}, /* 0x5f */ {"rts", M_NONE}, /* 0x60 */ {"adc", M_INDX}, /* 0x61 */ {"", M_NONE}, /* 0x62 */ {"", M_NONE}, /* 0x63 */ {"stz", M_ZP}, /* 0x64 */ /* 65C02 */ {"adc", M_ZP}, /* 0x65 */ {"ror", M_ZP}, /* 0x66 */ {"", M_NONE}, /* 0x67 */ {"pla", M_NONE}, /* 0x68 */ {"adc", M_IMM}, /* 0x69 */ {"ror", M_NONE}, /* 0x6a */ {"", M_NONE}, /* 0x6b */ {"jmp", M_IND}, /* 0x6c */ {"adc", M_ABS}, /* 0x6d */ {"ror", M_ABS}, /* 0x6e */ {"", M_NONE}, /* 0x6f */ {"bvs", M_REL}, /* 0x70 */ {"adc", M_INDX}, /* 0x71 */ {"adc", M_ZIND}, /* 0x72 */ /* 65C02 */ {"", M_NONE}, /* 0x73 */ {"stz", M_ZPX}, /* 0x74 */ /* 65C02 */ {"adc", M_ZPX}, /* 0x75 */ {"ror", M_ZPX}, /* 0x76 */ {"", M_NONE}, /* 0x77 */ {"sei", M_NONE}, /* 0x78 */ {"adc", M_ABSY}, /* 0x79 */ {"ply", M_NONE}, /* 0x7a */ /* 65C02 */ {"", M_NONE}, /* 0x7b */ {"jmp", M_ABINDX}, /* 0x7c */ /* 65C02 */ {"adc", M_ABSX}, /* 0x7d */ {"ror", M_ABSX}, /* 0x7e */ {"", M_NONE}, /* 0x7f */ {"bra", M_REL}, /* 0x80 */ /* 65C02 */ {"sta", M_INDX}, /* 0x81 */ {"", M_NONE}, /* 0x82 */ {"", M_NONE}, /* 0x83 */ {"sty", M_ZP}, /* 0x84 */ {"sta", M_ZP}, /* 0x85 */ {"stx", M_ZP}, /* 0x86 */ {"", M_NONE}, /* 0x87 */ {"dey", M_NONE}, /* 0x88 */ {"", M_NONE}, /* 0x89 */ {"txa", M_NONE}, /* 0x8a */ {"", M_NONE}, /* 0x8b */ {"sty", M_ABS}, /* 0x8c */ {"sta", M_ABS}, /* 0x8d */ {"stx", M_ABS}, /* 0x8e */ {"", M_NONE}, /* 0x8f */ {"bcc", M_REL}, /* 0x90 */ {"sta", M_INDY}, /* 0x91 */ {"sta", M_ZIND}, /* 0x92 */ /* 65C02 */ {"", M_NONE}, /* 0x93 */ {"sty", M_ZPX}, /* 0x94 */ {"sta", M_ZPX}, /* 0x95 */ {"stx", M_ZPX}, /* 0x96 */ {"", M_NONE}, /* 0x97 */ {"tya", M_NONE}, /* 0x98 */ {"sta", M_ABSY}, /* 0x99 */ {"txs", M_NONE}, /* 0x9a */ {"", M_NONE}, /* 0x9b */ {"stz", M_ABS}, /* 0x9c */ /* 65C02 */ {"sta", M_ABSX}, /* 0x9d */ {"stz", M_ABSX}, /* 0x9e */ /* 65C02 */ {"", M_NONE}, /* 0x9f */ {"ldy", M_IMM}, /* 0xa0 */ {"lda", M_INDX}, /* 0xa1 */ {"ldx", M_IMM}, /* 0xa2 */ {"", M_NONE}, /* 0xa3 */ {"ldy", M_ZP}, /* 0xa4 */ {"lda", M_ZP}, /* 0xa5 */ {"ldx", M_ZP}, /* 0xa6 */ {"", M_NONE}, /* 0xa7 */ {"tay", M_NONE}, /* 0xa8 */ {"lda", M_IMM}, /* 0xa9 */ {"tax", M_NONE}, /* 0xaa */ {"", M_NONE}, /* 0xab */ {"ldy", M_ABS}, /* 0xac */ {"lda", M_ABS}, /* 0xad */ {"ldx", M_ABS}, /* 0xae */ {"", M_NONE}, /* 0xaf */ {"bcs", M_REL}, /* 0xb0 */ {"lda", M_INDY}, /* 0xb1 */ {"lda", M_ZIND}, /* 0xb2 */ /* 65C02 */ {"", M_NONE}, /* 0xb3 */ {"ldy", M_ZPX}, /* 0xb4 */ {"lda", M_ZPX}, /* 0xb5 */ {"ldx", M_ZPY}, /* 0xb6 */ {"", M_NONE}, /* 0xb7 */ {"clv", M_NONE}, /* 0xb8 */ {"lda", M_ABSY}, /* 0xb9 */ {"tsx", M_NONE}, /* 0xba */ {"", M_NONE}, /* 0xbb */ {"ldy", M_ABSX}, /* 0xbc */ {"lda", M_ABSX}, /* 0xbd */ {"ldx", M_ABSY}, /* 0xbe */ {"", M_NONE}, /* 0xbf */ {"cpy", M_IMM}, /* 0xc0 */ {"cmp", M_INDX}, /* 0xc1 */ {"", M_NONE}, /* 0xc2 */ {"", M_NONE}, /* 0xc3 */ {"cpy", M_ZP}, /* 0xc4 */ {"cmp", M_ZP}, /* 0xc5 */ {"dec", M_ZP}, /* 0xc6 */ {"", M_NONE}, /* 0xc7 */ {"iny", M_NONE}, /* 0xc8 */ {"cmp", M_IMM}, /* 0xc9 */ {"dex", M_NONE}, /* 0xca */ {"", M_NONE}, /* 0xcb */ {"cpy", M_ABS}, /* 0xcc */ {"cmp", M_ABS}, /* 0xcd */ {"dec", M_ABS}, /* 0xce */ {"", M_NONE}, /* 0xcf */ {"bne", M_REL}, /* 0xd0 */ {"cmp", M_INDY}, /* 0xd1 */ {"cmp", M_ZIND}, /* 0xd2 */ /* 65C02 */ {"", M_NONE}, /* 0xd3 */ {"", M_NONE}, /* 0xd4 */ {"cmp", M_ZPX}, /* 0xd5 */ {"dec", M_ZPX}, /* 0xd6 */ {"", M_NONE}, /* 0xd7 */ {"cld", M_NONE}, /* 0xd8 */ {"cmp", M_ABSY}, /* 0xd9 */ {"phx", M_NONE}, /* 0xda */ /* 65C02 */ {"", M_NONE}, /* 0xdb */ {"", M_NONE}, /* 0xdc */ {"cmp", M_ABSX}, /* 0xdd */ {"dec", M_ABSX}, /* 0xde */ {"", M_NONE}, /* 0xdf */ {"cpx", M_IMM}, /* 0xe0 */ {"sbc", M_INDX}, /* 0xe1 */ {"", M_NONE}, /* 0xe2 */ {"", M_NONE}, /* 0xe3 */ {"cpx", M_ZP}, /* 0xe4 */ {"sbc", M_ZP}, /* 0xe5 */ {"inc", M_ZP}, /* 0xe6 */ {"", M_NONE}, /* 0xe7 */ {"inx", M_NONE}, /* 0xe8 */ {"sbc", M_IMM}, /* 0xe9 */ {"nop", M_NONE}, /* 0xea */ {"", M_NONE}, /* 0xeb */ {"cpx", M_ABS}, /* 0xec */ {"sbc", M_ABS}, /* 0xed */ {"inc", M_ABS}, /* 0xee */ {"", M_NONE}, /* 0xef */ {"beq", M_REL}, /* 0xf0 */ {"sbc", M_INDY}, /* 0xf1 */ {"sbc", M_ZIND}, /* 0xf2 */ /* 65C02 */ {"", M_NONE}, /* 0xf3 */ {"", M_NONE}, /* 0xf4 */ {"sbc", M_ZPX}, /* 0xf5 */ {"inc", M_ZPX}, /* 0xf6 */ {"", M_NONE}, /* 0xf7 */ {"sed", M_NONE}, /* 0xf8 */ {"sbc", M_ABSY}, /* 0xf9 */ {"plx", M_NONE}, /* 0xfa */ /* 65C02 */ {"", M_NONE}, /* 0xfb */ {"", M_NONE}, /* 0xfc */ {"sbc", M_ABSX}, /* 0xfd */ {"inc", M_ABSX}, /* 0xfe */ {"", M_NONE}, /* 0xff */ }; diss(pc, fp) unsigned short pc; FILE *fp; { char *s; int count; int tmp; unsigned short addr; unsigned char one, two, three; fprintf(fp, "%.4X: ", pc); addr = pc; one = mem[pc++]; two = mem[pc++]; three = mem[pc++]; s = opcode[one].name; if (s == NULL || *s == '\0') s = "???"; switch (opcode[one].add_mode) { case 0: fprintf(fp, "%.2x %s ", one, s); count = 1; break; case M_ZP: fprintf(fp, "%.2x %.2x %s $%.2x ", one, two, s, two); count = 2; break; case M_ZPX: fprintf(fp, "%.2x %.2x %s $%.2x,X ", one, two, s, two); count = 2; break; case M_ZPY: fprintf(fp, "%.2x %.2x %s $%.2x,Y ", one, two, s, two); count = 2; break; case M_IND: fprintf(fp, "%.2x %.2x %.2x %s ($%.4x) ", one, two, three, s, join(two, three)); count = 3; break; case M_INDX: fprintf(fp, "%.2x %.2x %s ($%.2x,X) ", one, two, s, two); count = 2; break; case M_INDY: fprintf(fp, "%.2x %.2x %s ($%.2x),Y ", one, two, s, two); count = 2; break; case M_ABS: fprintf(fp, "%.2x %.2x %.2x %s $%.4x ", one, two, three, s, join(two, three)); count = 3; break; case M_ABSX: fprintf(fp, "%.2x %.2x %.2x %s $%.4x,X ", one, two, three, s, join(two, three)); count = 3; break; case M_ABSY: fprintf(fp, "%.2x %.2x %.2x %s $%.4x,Y ", one, two, three, s, join(two, three)); count = 3; break; case M_IMM: fprintf(fp, "%.2x %.2x %s #$%.2x ", one, two, s, two); count = 2; break; case M_REL: tmp = two; if (tmp > 127) tmp = tmp - 256; tmp += addr + 2; tmp &= 0xFFFF; fprintf(fp, "%.2x %.2x %s $%.4x ", one, two, s, tmp); count = 2; break; case M_ZIND: fprintf(fp, "%.2x %.2x %s ($%.2x) ", one, two, s, two); count = 2; break; case M_ABINDX: fprintf(fp, "%.2x %.2x %.2x %s ($%.4x,X)", one, two, three, s, join(two, three)); count = 3; break; default: fprintf(fp, "%.2x %s ", "???", one); count = 1; } return(count); } flags(fp) FILE *fp; { fprintf(fp, " A=%.2X X=%.2X Y=%.2X SP=%.2X", A, X, Y, Sp); fprintf(fp, " N%d V%d B%d D%d I%d Z%d C%d\n", !!N, !!V, !!B, !!D, !!I, !NZ, !!C); } @EOF chmod 644 table.c echo x - vidout.c cat >vidout.c <<'@EOF' /* * 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 #include "a2.h" #define WNDLFT 0x20 #define WNDWDTH 0x21 #define WNDTOP 0x22 #define WNDBTM 0x23 #define CH 0x24 #define CV 0x25 #define BASL 0x28 #define BASH 0x29 #define BAS2L 0x2A #define BAS2H 0x2B /* * VIDOUT at $FBFD */ vidout() { unsigned short ptr; if (A >= 0xA0 || A < 0x80) { ptr = join(mem[BASL], mem[BASH]) + mem[CH]; set_text1f(ptr, A); mem[CH]++; if (mem[CH] >= mem[WNDWDTH]) mem[CH] = 0; else { DO_RTS; return; } } else if (A == 0x8D) mem[CH] = 0; else if (A != 0x8A) { Pc = 0xFC0C; return; } A = ++mem[CV]; if (A < mem[WNDBTM]) { Pc = 0xFC24; return; } mem[CV]--; scroll(); } /* * SCROLL at $FC70 */ scroll() { int top; unsigned short bas, bas2, ptr; int width; int i; int scrl2_normal; if (mem[0x21] == 40 && mem[0x22] == 0 && mem[0x23] == 24) { MoveCursor(term_lines, 0); putchar('\n'); last_line = -1; last_col = -1; fflush(stdout); scrl2_normal = FALSE; } else scrl2_normal = TRUE; top = mem[WNDTOP]; width = mem[WNDWDTH] - 1; bas = text1[top % 32] + mem[WNDLFT]; while (1) { bas2 = bas; if (++top >= mem[WNDBTM]) { mem[BASL] = low(bas); mem[BASH] = high(bas); Pc = 0xFC95; fflush(stdout); return; } bas = text1[top % 32] + mem[WNDLFT]; ptr = bas; if (scrl2_normal) for (i = 0; i <= width; i++) set_text1(bas2++, mem[ptr++]); else for (i = 0; i <= width; i++) mem[bas2++] = mem[ptr++]; } } @EOF chmod 644 vidout.c exit 0