From NISC.SRI.COM!unix!Teknowledge.COM!uw-beaver!rice!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!usc!apple!oracle!news Sun Apr 15 01:21:03 PDT 1990 Article 772 of comp.binaries.apple2: Path: NISC.SRI.COM!unix!Teknowledge.COM!uw-beaver!rice!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!usc!apple!oracle!news >From: pnakada@oracle.com (Paul Nakada) Newsgroups: comp.binaries.apple2 Subject: Repost: Apple ][+ simulator for UNIX/BSD boxes Part 02/03 Message-ID: Date: 13 Apr 90 19:27:43 GMT Sender: news@oracle.com Organization: Oracle Corporation, Belmont, CA Lines: 847 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # If this archive is complete, you will see the following message at the end: # "End of archive 2 (of 2)." # Contents: Makefile apple.h main.c mega2.c # Wrapped by pnakada@pnakada on Thu Apr 12 00:46:04 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(1187 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X#Makefile for Apple ][ Emulator X#(C) 1989 Ben Koning [556498717 408/738-1763 ben@apple.com] X# X X#Local printing command: XPRINT = lpr -Psimplex X X#Apple.II is split up as follows: XOBJ = main.o 6502.o mega2.o debug.o X X#Make normal version: Xdebug: ${OBJ} apple.h X cc -g $(OBJ) -lcurses -ltermcap Xlint: X lint main.c 6502.c mega2.c debug.c -lcurses -ltermcap X X#Make final optimized version: Xfinal: X touch apple.h X make debug X strip a.out X mv a.out Apple.II X make clean X X#Make profiling version: Xprofil: X cc -pg main.c 6502.c mega2.c debug.c -lcurses -ltermcap X X#Building modules from source: Xmain.o: main.c apple.h X cc -c -g main.c X6502.o: 6502.c apple.h X cc -c -g 6502.c Xmega2.o: mega2.c apple.h X cc -c -g mega2.c Xdebug.o: debug.c apple.h X cc -c -g debug.c X X#Cleanup of directory: Xclean: X rm -f ${OBJ} X rm -f file X rm -f a.out X rm -f core X X#Printout without long ROM listings: Xprint: X rm -f file X touch file X pr README >> file X pr Makefile >> file X pr *.h >> file X pr main.c >> file X pr 6502.c >> file X pr mega2.c >> file X $(PRINT) file X rm -f file X wc *.h *.c X X#Printout with long copyrighted ROM listings: Xprintall: X make print END_OF_FILE echo shar: NEWLINE appended to \"'Makefile'\" if test 1188 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'apple.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'apple.h'\" else echo shar: Extracting \"'apple.h'\" \(1242 characters\) sed "s/^X//" >'apple.h' <<'END_OF_FILE' X X/* X *apple.h -- Globals' xdefs and equates for system calls for Apple ][ Emulator X *(C) 1989 Ben Koning [556498717 408/738-1763 ben@apple.com] X */ X X X X/* Character which ends the emulation: */ X X#define MEGAQUITKEY 001 /* Control-A */ X X X X/* XENIX/BSD - Compatible includes: */ X X#ifndef BUFSIZ X#include X#endif X X#ifndef isalpha X#include X#endif X X#ifndef CBREAK X#include X#endif X X#ifndef TIOCGETP X#include X#endif X X#ifndef O_NDELAY X#include X#endif X X#define BYTE unsigned char X#define ADDR int X X X X/* 6502 Globals: */ X Xextern int A,X,Y,P,S; Xextern ADDR PPC; X X X X X X/* Emulation Globals: */ X Xextern BYTE MMemory[]; Xextern BYTE Rom[]; Xextern BYTE MRam[]; Xextern BYTE MRam1[]; Xextern BYTE MRam2[]; Xextern BYTE RamRead; Xextern BYTE RamWrite; Xextern BYTE Bank2Enable; X Xextern BYTE MegaRand; Xextern BYTE MegaLastKey; Xextern BYTE MegaQuitDetect; Xextern int DebugSingle; Xextern int DebugTrace; Xextern ADDR DebugBreak; X X X/* Apple ROM Contents: */ X Xextern BYTE MegaGetMem(); X X X/* Termcap stuff: */ X X Xextern void Debugger(); Xextern void MegaShutDown(); Xextern void MegaStartUp(); Xextern void MegaPutMem(); X Xextern void prodos(); X Xextern void CPUShutDown(); Xextern void CPUReset(); Xextern void CPUExecute(); END_OF_FILE echo shar: NEWLINE appended to \"'apple.h'\" if test 1243 -ne `wc -c <'apple.h'`; then echo shar: \"'apple.h'\" unpacked with wrong size! fi # end of 'apple.h' fi if test -f 'main.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'main.c'\" else echo shar: Extracting \"'main.c'\" \(2227 characters\) sed "s/^X//" >'main.c' <<'END_OF_FILE' X X/* X *main.c -- Globals and emulation setup for Apple ][ Emulator X *(C) 1989 Ben Koning [556498717 408/738-1763 ben@apple.com] X */ X X#include "apple.h" X#include X#define REF_DELAY 2000 X Xmain (argc,argv) X Xint argc; Xchar *argv []; X X{ X short int byte; X int i, addr; /* Loop iterators */ X int refdelay = REF_DELAY; X FILE *fp; X char *D0FILE = "APPLESOFT.ROM", X *F8FILE = "AUTOSTART.ROM" ; X X /* Interpret args: 'invokename [-t] [-m] [-i]' */ X for (i = 1; i <= argc-1; i++) X { X if (!strcmp (argv [i],"-t")) X DebugSingle = 1; X else X if (!strcmp (argv [i],"-m")) X F8FILE = "MONITOR.ROM"; X else X if (!strcmp (argv [i],"-i")) X D0FILE = "INTEGER.ROM"; X else X { X (void)fprintf (stderr,"Usage: %s [-t] [-m] [-i]\n", X argv [0]); X exit (1); X } X } X X /* Print banner message: */ X (void)fprintf (stderr,"%s: Apple ][ Emulation - Ben Koning - v1.0\n", X argv [0]); X X (void)initscr(); X X /*--------------------------------------------------*\ X Load the 'ROM' with the appropriate 6502 code: X \*--------------------------------------------------*/ X fp = fopen (D0FILE, "r"); X for (addr = 0xd000; addr <= 0xf7ff; addr++) X Rom [addr - 0xd000] = fgetc (fp); X (void)fclose (fp); X X fp = fopen (F8FILE, "r"); X for (addr = 0xf800; addr <= 0xffff; addr++) X Rom [addr - 0xd000] = fgetc (fp); X (void)fclose (fp); X X /*--------------------------------------------------*\ X load prodos as $2000 X \*--------------------------------------------------*/ X fp = fopen ("PRODOS", "r"); X addr = 0x2000; X while ((byte = fgetc (fp)) != EOF) X MMemory [addr++] = byte; X (void)fclose (fp); X X /* Make sure banner message is seen: */ X sleep (2); X X /* Initialize the emulation: */ X MegaStartUp (); X CPUReset (); X X /*--------------------------------------------------*\ X Run it until user wants to quit: X \*--------------------------------------------------*/ X while (!MegaQuitDetect) X { X CPUExecute (); X if (!(--refdelay)) X { X refresh(); X refdelay = REF_DELAY; X } X if (MegaQuitDetect || DebugSingle || DebugTrace) X Debugger(); X } X X /* Exit cleanly: */ X MegaShutDown (); X exit (0); X} X X END_OF_FILE echo shar: NEWLINE appended to \"'main.c'\" if test 2228 -ne `wc -c <'main.c'`; then echo shar: \"'main.c'\" unpacked with wrong size! fi # end of 'main.c' fi if test -f 'mega2.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mega2.c'\" else echo shar: Extracting \"'mega2.c'\" \(12594 characters\) sed "s/^X//" >'mega2.c' <<'END_OF_FILE' X/* X *mega2.c -- Apple ][ soft switches->UNIX emulation for Apple ][ Emulator X *(C) 1989 Ben Koning [556498717 408/738-1763 ben@apple.com] X */ X X#include "apple.h" X#include X X X/* X * Termcap globals: X */ X X X/* X * Emulation globals: X */ X XBYTE MMemory [49152]; /* Main memory */ XBYTE Rom [12288]; /* 12K ROM bank of Main memory */ XBYTE MRam [12288]; /* 12K RAM bank of Main memory */ XBYTE MRam1 [4096]; /* Main bank 1 $D000-$DFFF */ XBYTE MRam2 [4096]; /* Main bank 2 $D000-$DFFF */ XBYTE RamRead = 0; /* set if 16K RAM readable */ XBYTE RamWrite = 0; /* set if 16K RAM writeable */ XBYTE Bank2Enable = 0; /* set if bank 2 Ram enabled */ X XBYTE MegaRand = 0; /* Always contains 8-bit random number */ XBYTE MegaLastKey = 0; /* $C00X keyboard latch value */ XBYTE MegaQuitDetect = 0; /* Set if user requests to quit */ X Xvoid PutC010(); Xvoid Put0400(); Xvoid GetC080(); XBYTE GetC000(); XBYTE GetC010(); XBYTE GetC030(); X Xvoid ProInit(); Xvoid ProFormat(); Xvoid ProRead(); Xvoid ProWrite(); Xvoid ProStatus(); X X/* X * Base address table for 24 lines of text/lores page 1 ($400..$7F8); X * 40 bytes for each line. Note that screen "holes" exist: X */ X Xint LBasCalc [24] = X X{ X1024, X1152, X1280, X1408, X1536, X1664, X1792, X1920, X1064, X1192, X1320, X1448, X1576, X1704, X1832, X1960, X1104, X1232, X1360, X1488, X1616, X1744, X1872, X2000 X}; X X#define MegaPutChar(c) addch(c) X X/**************************************************************************/ X/* Dispatch routines: The MegaPutMem and MegaGetMem, below, have default */ X/* behavior for I/O space. They may also contain calls to other routines */ X/* in this file which handle Apple II behavior. If these latter routines */ X/* need initialization/shutdown, that code should be placed in the two */ X/* MegaStartUp and MegaShutDown routines, below. */ X/**************************************************************************/ X X#ifdef NEVER Xvoid MegaPutChar (c) Xchar c; /* This makes a function out of the "putchar" macro */ X X{ X addch (c); X} X#endif X X/* This routine is called at emulation startup time. All initialization X stuff, like setting terminal modes, opening files, etc. goes here. */ Xvoid MegaStartUp () X{ X register int i; /* Iterator */ X X /* init the pseudo disk */ X ProInit(); X X /* Set input modes on terminal: */ X noecho(); X raw(); X X /* Fill 40-column screen with simulated initial memory pattern: */ X clear(); X for (i = 0; i <= 23; i++) X mvaddstr (i, 0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); X X refresh(); X X /* Initialize some variables: */ X MegaQuitDetect = 0; X MegaLastKey = 0; X MegaRand = 0; X} X X X X/* This routine is called at emulation shutdown time. All things X started in MegaStartUp, above, should be cleaned up here. */ Xvoid MegaShutDown () X{ X /* Clear screen: */ X clear(); X refresh(); X X /* Reset sane modes on terminal: */ X echo(); X noraw(); X endwin(); X} X X/* This routine handles ALL stores to the 64K address space, in order to X faciliate special Apple ][ - specific effects. Not all behaviors may X be implemented; to install a new one, install the call in this routine. X Returns: Nothing. */ Xvoid MegaPutMem (addr, byte) Xregister ADDR addr; Xregister BYTE byte; X{ X /* Make sure these are in range: */ X addr &= 0xffff; X byte &= 0xff; X X /* Do random number generation: */ X MegaRand = (MegaRand + addr + byte) & 0xff; X X /* If in ROM, we are done here: */ X if (addr >= 0xd000 && !RamWrite) X { X/* Rom[addr - 0xd000] = byte; */ X return; X } X X if (addr < 0xc000) /* Main memory */ X MMemory [addr] = byte; X else if (addr >= 0xd000 && addr < 0xe000) /* 4K RAM Banks */ X { X BYTE *bank = Bank2Enable ? MRam2 : MRam1; X X bank [addr - 0xd000] = byte; X } X else if (addr >= 0xe000) /* 8K RAM Bank */ X MRam [addr - 0xe000] = byte; X else if ((addr >= 0xc010) && (addr <= 0xc01f)) /* soft switches */ X PutC010 (0); X else if (addr >= 0xc080 && addr < 0xc090) X GetC080 (addr); X X /* Now do the appropriate memory-mapped OUTPUT functions, if any: */ X if ((addr >= 0x0400) && (addr < 0x0800)) X Put0400 (addr, byte); X} X X X/* This routine handles ALL fetches from the 64K address space, in order to X facilitate special Apple ][ - specific effects. Not all behaviors may X be implemented; to install a new one, install the call in this routine. X Returns: Value at location (could be random if I/O, etc.). */ XBYTE MegaGetMem (addr) Xregister ADDR addr; X{ X register BYTE data; /* Data from memory space to be returned */ X X /* Make sure we're in range: */ X addr &= 0xffff; X X /* If we're just in ROM or RAM, it's easy: */ X if (addr < 0xc000) X return (MMemory [addr]); X else if (addr >= 0xd000 && !RamRead) /* rom read enabled */ X return (Rom[addr - 0xd000]); X else if (addr >= 0xe000) /* 8K RAM read */ X return (MRam[addr - 0xe000]); X else if (addr >= 0xd000 && addr < 0xe000) /* 4K Bank RAM */ X return (Bank2Enable ? MRam2[addr - 0xd000] : MRam1[addr - 0xd000]); X X X /* We must be in C000 space. Default to random value: */ X data = MegaRand & 0xff; X MegaRand = (MegaRand + addr * 25 + data) & 0xff; X X /* Now do the appropriate memory-mapped INPUT functions, if any: */ X if ((addr >= 0xc000) && (addr <= 0xc00f)) X data = GetC000 (); X else if ((addr >= 0xc010) && (addr <= 0xc01f)) X data = GetC010 (); X else if ((addr >= 0xc030) && (addr <= 0xc03f)) X data = GetC030 (); X else if ((addr >= 0xc080) && (addr <= 0xc08f)) X GetC080 (addr); X else if (addr == 0xc011) X data = 0xFF * Bank2Enable; X else if (addr == 0xc012) X data = 0xFF * RamRead; X else if (addr == 0xc701) X data = 0x20; X else if (addr == 0xc703) X data = 0x00; X else if (addr == 0xc705) X data = 0x03; X else if (addr == 0xc7ff) X data = 0x80; X else if (addr == 0xc7fe) X data = 0x1f; X else if (addr == 0xc7fc) X data = 0x00; X else if (addr == 0xc7fd) X data = 0x00; X else if (addr == 0xc780) X data = 0x60; X X /* Return the data we came up with to the user: */ X return (BYTE) (data & 0xff); X} X X X X X X/**************************************************************************/ X/* Memory-Mapped I/O routines: These routines actually perform the spe- */ X/* cific UNIX operations for get/put to certain addresses. Not all Get */ X/* or Put routines must necessarily have a companion Put or Get routine: */ X/* */ X/* * GetXXXXXX: Return a byte of data from an I/O address */ X/* * PutXXXXXX: Receive a byte of data for an I/O address */ X/* */ X/**************************************************************************/ X X X X X X/* Get keyboard data in low 7 bits. Msb indicates if hit since last C010: */ XBYTE GetC000 () X{ X register int fflags; X char data = '*'; X X /* Set nonblocking input: */ X fflags = fcntl (0, F_GETFL, 0); X (void)fcntl (0, F_SETFL, fflags | O_NDELAY); X X /* See if a key was pressed. If yes, update and set hi bit; */ X /* else, leave keyboard latch with last value: */ X if (read (0, &data, 1) > 0) X MegaLastKey = (int) data | 0x80; X X /* Reset nonblocking input: */ X (void)fcntl (0, F_SETFL, fflags); X X /* See if user wants to quit: */ X MegaQuitDetect = (data == MEGAQUITKEY); X X return (BYTE)MegaLastKey; X} X X X X X X/* Clear keyboard strobe for C000 msb: */ XBYTE GetC010 () X{ X MegaLastKey &= 0x7f; /* Clear strobe bit */ X return (BYTE)(MegaRand & 0xff); X} X Xvoid GetC080 (addr) XADDR addr; X{ X switch (addr & 0x000F) X { X case 0x00: X RamRead = 1; X RamWrite = 0; X Bank2Enable = 1; X break; X case 0x01: X RamRead = 0; X RamWrite = 1; X Bank2Enable = 1; X break; X case 0x02: X RamRead = 0; X RamWrite = 0; X Bank2Enable = 1; X break; X case 0x03: X RamRead = 1; X RamWrite = 1; X Bank2Enable = 1; X break; X case 0x08: X RamRead = 1; X RamWrite = 0; X Bank2Enable = 0; X break; X case 0x09: X RamRead = 0; X RamWrite = 1; X Bank2Enable = 0; X break; X case 0x0a: X RamRead = 0; X RamWrite = 0; X Bank2Enable = 0; X break; X case 0x0b: X RamRead = 1; X RamWrite = 1; X Bank2Enable = 0; X break; X } X} X X/*ARGSUSED*/ Xvoid PutC010 (data) XBYTE data; X{ X (void)GetC010 (); /* Same thing; either one works */ X} X X X X/* Beeps speaker if accessed a lot: */ XBYTE GetC030 () X{ X static int count = 0; X X if (count++ >= 100) X { X count = 0; X /* tputs (TcapBeep,1,MegaPutChar); */ X /* putchar (7); */ X /* fflush (stdout); */ X } X return (BYTE)(MegaRand & 0xff); X} X X X/* Handles stores to text/lowres page 1 memory */ Xvoid Put0400 (addr,data) Xregister ADDR addr; X BYTE data; X{ X register int linenum; /* Searching for Y-coordinate */ X register int columnnum; /* Searching for X-coordinate */ X int screenhole = 1; /* Are we in screen hole? */ X X /* Find which line the given address is in: */ X for (linenum = 0; linenum <= 23; linenum++) X if ( (addr >= LBasCalc [linenum]) && X (addr <= (LBasCalc [linenum] + 39)) ) X { X columnnum = addr - LBasCalc [linenum]; X screenhole = 0; X break; X } X X /* If not on screen, don't draw anything: */ X if (screenhole) X return; X X /* Put the terminal cursor at the right location on the screen: */ X /* We assume 80x24 terminal; no need to avoid drawing on last char. */ X move (linenum, columnnum); X X /* X Set terminal into appropriate output mode and do it: X tputs (TcapInverse,1,MegaPutChar); X */ X if (data < 64) X { X /* attron (A_STANDOUT); */ X standout(); X if (data < 32) X data += 64; X } X else if ((data < 128) && (data > 63)) X { X standout(); X if (data > 95) X data -= 64; X } X else X data = data & 127; X if (!iscntrl ((char) data)) X MegaPutChar ((char) data); X else X MegaPutChar ((char) (data - 64)); X standend(); X} X X#define _setN_(b) if ((b)!=0) P |= 128; else P &= 0x7f X#define _setV_(b) if ((b)!=0) P |= 64; else P &= 0xbf X /* This bit not implemented */ X#define _setB_(b) if ((b)!=0) P |= 16; else P &= 0xef X#define _setD_(b) if ((b)!=0) P |= 8; else P &= 0xf7 X#define _setI_(b) if ((b)!=0) P |= 4; else P &= 0xfb X#define _setZ_(b) if ((b)!=0) P |= 2; else P &= 0xfd X#define _setC_(b) if ((b)!=0) P |= 1; else P &= 0xfe X Xstatic unsigned char buffer[512]; XFILE *disk1, /* slot 7, drive 1 280 block 5.25 floppy */ X *disk2; /* slot 7, drive 2 1024 blocks "hard disk" */ X X#define NBLOCKSD1 280 X#define NBLOCKSD2 1024 X Xvoid ProInit () X{ X MegaPutMem (0x0043, (BYTE)0x70); /* boot disk */ X disk1 = fopen ("PRODOS.IMAGE.D1", "r+"); X disk2 = fopen ("PRODOS.IMAGE.D2", "r+"); X} X Xvoid ProFormat (drive) Xint drive; X{ X int numblocks = drive ? NBLOCKSD2 : NBLOCKSD1; X FILE *disk = drive ? disk2 : disk1; X X (void)fseek (disk, (long)(512 * numblocks), 0); X (void)fwrite (" ", 1, 1, disk); X} X Xvoid ProRead (drive) Xint drive; X{ X register int i; X int block = MegaGetMem (0x46) + MegaGetMem (0x47) * 0x0100; X int buf = MegaGetMem (0x44) + MegaGetMem (0x45) * 0x0100; X FILE *disk = drive ? disk2 : disk1; X X (void)fseek (disk, (long)(block * 512), 0); X X (void)fread ((char *)buffer, 1, 512, disk); X for (i = 0; i < 512; i++) X MegaPutMem (buf + i, (BYTE)buffer[i]); X _setC_(0); /* CLC */ X A = 0; X} X Xvoid ProWrite (drive) Xint drive; X{ X register int i; X int block = MegaGetMem (0x46) + MegaGetMem (0x47) * 0x0100; X int buf = MegaGetMem (0x44) + MegaGetMem (0x45) * 0x0100; X FILE *disk = drive ? disk2 : disk1; X X (void)fseek (disk, (long)(block * 512), 0); X X for (i = 0; i < 512; i++) X buffer[i] = MegaGetMem (buf + i); X X (void)fwrite ((char *)buffer, 1, 512, disk); X _setC_(0); /* CLC */ X A = 0; X} X Xvoid ProStatus (drive) Xint drive; X{ X int numblocks = drive ? NBLOCKSD2 : NBLOCKSD1; X X _setC_(0); /* CLC */ X A = 0; /* LDA #0 */ X Y = numblocks / 256; X X = numblocks % 256; X} X Xvoid prodos() X{ X int drive = ((MegaGetMem (0x43) >= 128) ? 1 : 0); X X switch (MegaGetMem (0x42)) X { X case 0: X ProStatus (drive); break; X case 1: X ProRead (drive); break; X case 2: X ProWrite (drive); break; X case 3: X ProFormat (drive); break; X } X} X END_OF_FILE echo shar: NEWLINE appended to \"'mega2.c'\" if test 12595 -ne `wc -c <'mega2.c'`; then echo shar: \"'mega2.c'\" unpacked with wrong size! fi # end of 'mega2.c' fi echo shar: End of archive 2 \(of 2\). cp /dev/null ark2isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0