commit cf770f0a3d0a3813eea849d35849b840f8359ab6 Author: Mark Aufflick Date: Tue Oct 18 14:49:35 2011 +1100 v0.86 sources and binaries (earliest available on website) diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..56bedb5 --- /dev/null +++ b/CHANGES @@ -0,0 +1,410 @@ + +Changes in KEGS v0.86 since v0.85 (03/23/04) +- Add patch for Solaris sound by Jonathan Kalbfeld. +- Fix so that F4 enters config panel even while running Prosel-16 +- Major mouse pointer changes, based on some ideas from Geoff Weiss. + The GSOS mouse now exactly tracks the host pointer automatically. +- Fixed an accidental debug halt when Prosel-16 disables the keyboard/mouse. + +Changes in KEGS v0.85 since v0.84 (01/09/04) +- Fix some minor 65816 bank-crossing bugs. +- Add -noignhalt to allow user to stop on code red halts. +- Fix Win32 capslock problem as reported by Edward Moore +- Fixed DreamVoir app on the sample image (it was corrupt) + +Changes in KEGS v0.84 since v0.83 (11/21/03) +- Add new speed, 8.0MHz directly using right-clicking or F6. +- Sim speed and Video update interval added to Config panel. +- Various cycle timing bugs in engine_c.c fixed. +- Add Config Panel entry to mask serial output to 7-bit, to enable PR#2 to + work better with an external telnet. +- In Config Panel file selection, typing a letter jumps to the first file + beginning with that letter. +- Fixed various serial socket bugs. Now you can disconnect a telnet session + and start a new one, and a Linux hang is fixed. +- Default GS memory size increased to 8MB. +- Small fix to double-hires color table. +- X windows can now send displays to other-endian X servers. + +Changes in KEGS v0.83 since v0.82 (11/19/03) +- Add Memory Size to config panel, with support for up to 14MB of memory + (Geoff Weiss) +- Add $C04F EMUBYTE support which Bernie II the Rescue defined. (Geoff Weiss) +- Fix $CFFF code red's reported by David Wilson. +- Add smartport $C70A Format routine (David Wilson). + +Changes in KEGS v0.82 since v0.81 (11/06/03) +- Fix superhires display glitch introduced in v0.81. +- Improved border handling--XMAS demo looks great. +- Fix some X build problems introduced in v0.81. + +Changes in KEGS v0.81 since v0.80 (11/04/03) +- Code Red/Yellow warnings about emulation stability +- Windows file browsing fixes +- Built-in C600 ROM for Apple II 5.25" game compatibility +- Turns key repeat back on when exiting from X-windows version +- Windows F8 captures the cursor + +Changes in KEGS v0.80 since v0.71 (10/31/03) +- Configuration Panel means no more hand-editing configuration files +- All emulator state is now saved in "config.kegs" +- 3200 color pictures! Video system much improved for display accuracy. +- F8 Pointer grabbing works on Mac +- ZipGS emulation + +Changes in KEGS v0.71 since v0.70 (11/20/02) +- Improved double-hires colors a lot. -dhr140 is no longer the default +- Airheart relies on the PC going from 0xffff to 0x0000, so I undid the + change from KEGS v0.54 which allowed PC to overflow to 0x10000. + This slows KEGS down by about 5%. +- Fixed X shared memory bug in KEGS v0.70 with fix from Jonathan Stark. + +Changes in KEGS v0.70 since v0.60 (11/18/02) +- New buttons: Middle button is enter-debugger, and right button changes speed +- New function key mapping (see README.kegs) +- Mac OS X port +- Win32 port +- Centralized much of what had been "xdriver.c" code into video.c, to move + true platform-specific stuff into the various *driver.c codes. + Kimage struct tracks video display buffers in a dev-independent way. + From video.c, the calls to the platform code start with "x_" mostly. + Code in video.c cleaned up somewhat. + Borders are now always in native buffer format, while text/hires/ + and superhires are in 8-bit buffers and translated to native later. +- Mac and Windows sound are all done in one process--no child sound process. +- Revamped key press handling and mouse clicks--all is now handled in + adb.c for a consistent user interface. Now KEGS implements the + same function keys on all platforms. See README.kegs for fn key maps. +- I copied the debugger help from Frederic Devernay's KEGS-SDL port. +- Fixed an old IWM bug causing bad nibblization due to using uninit vars. +- Gilles Tschopp workaround to use corrupted 2IMG files (from KEGS-OSX). +- Gilles Tschopp provided code to zero //gs memory at startup (from KEGS-OSX) +- Simple code to try to use Mac Diskcopy format disks +- Ignore writes to 0xc0a8 +- Search in $HOME and the launch directory (for mac) for kegs_conf/ROM +- Remove font65.sim file by integrating it into kegsfont.h. +- "-bw" option forces black and white hires mode. + + +Changes in KEGS v0.60 since v0.59 (10/03/00) +- The 16-bit colors were still wrong due to another coding error. It would + be much easier to get this right if I had a 16-bit color display... + A user says it works now. + +Changes in KEGS v0.59 since v0.58 (7/07/00) +- Added support for multiple paths to the default files and also multiple + names for many default files. This should make the .rpm distribution + work better. +- Add another keycode to mean break according to mic@research.nj.nec.com. +- Add support for various ROMs to get plugged into slot 1-7. +- Fix code so that it should compile on 64-bit platforms. + +Changes in KEGS v0.58 since v0.57 (2/08/00) +- Setting the execute bit on the disk image no longer means no-write-thru. + Too many new users were getting confused by this. +- Fixed another bug with Apple //e bank switching created by v0.56 + Reported by phoenyx. +- Add command line option "-v" to turn on some verbose debugging flags. +- Fixed potential core-dump bug with non-8 bit visuals. +- Fixed double-lo-res color problem. +- The X driver should work with any visual depth display now and get the + colors right. Ian Schmidt reported his 16-bit card had bad colors. + +Changes in KEGS v0.57 since v0.56 (12/27/99) +- Another try at making timezone stuff work across all Unix variants. + Let me know if the time in the Apple //gs control panel doesn't + match your real local time. +- Fix a bug created in v0.56 where the fast //e bank switch code had a typo. + This prevented ZBasic from working correctly. + +Changes in KEGS v0.56 since v0.55 (10/31/99) +- Faster Apple //e bank switch emulation. +- Simplified number of global variables for various softswitches. +- Fixed a bug which made 3.5" and 5.25" disk access much slower than necessary. +- Improved scan-line interrupt accuracy (lets MEGADEMO run). +- Improved sound interrupt accuracy (was hoping this would fix some sound + issues, but it doesn't seem to help). +- Add Mode_switch as an alias for the Option key +- I noticed the //gs self-tests were broken again--fixed. + +Changes in KEGS v0.55 since v0.54 (10/19/99) +- In LOG_PC debug aid, add cycles to the trace +- Fix MEGADEMO bug where 3.5" disks weren't properly ejected. Needed to + look at iwm.motor_on35 not iwm.motor_on. +- Temp fix for MEGADEMO to not halt if shadow-in-all-banks is on in $c036. +- Another MEGADEMO fix to not take a scan-line int if the SCB was cleared + right before the raster got to this line. +- Fix bug in smartport.c that was causing core dumps if you tried to init + a disk is s7dx. + +Changes in KEGS v0.54 since v0.53 (10/10/99) +- Add support for Out Of This World's direct reading of ADB RAM loc 0xb to + get key status. This lets shift/control work in OOTW. +- Code simplification to get rid of most set_halt() calls and use halt_printf. +- Speed improvement: track kpc (merged kbank and pc in one 32 bit variable) + which makes the inner loop faster. This does make KEGS not + accurately model a 65816 code crossing bank boundaries, but just + about every other emulator gets it wrong, and the speed improvement + is 5-10%. And I don't know of any code which relies on it + working correctly. +- Fix to allow better GS/OS compatibility: after each smartport call, + set 0x7f8 = 0xc7. +- Fixed ZipGS emulation bug where KEGS was not re-locking Zip at the right + time, which made double-hires not work after booting GS/OS. + +Changes in KEGS v0.53 since v0.52 (8/3/99) +- Move all the "fcycles" timing calculations to use double instead of float. +- Fix display shadowing bug reported by "phoenyx" which caused the text + display to not always be updated correctly with funny bank switching. +- Added the "Home" key as an alias for the '=' on the keypad. +- Changed the way X modifiers are interpreted to increase compatibility of + Caps Lock to more X servers. +- Add -dhr140 option to use old double-hires color mode that results in + exactly 140 horizontal pixels with no bleeding. It's set default + to "on" for now while I work out double-hires colors. +- Started adding some ZipGS compatibility--control panels run, but all + the controls are effectively ignored by KEGS. + +Changes in KEGS v0.52 since v0.51 (6/27/99) +- Small speed-up of interpreter loop to avoid checking the global variable + "halt_sim" after every instruction. +- Smartport fixes to avoid halts when the SCSI CD player NDA is installed. +- Fix to autodetect X visual depth (it didn't work at all in v0.51). +- Fix to HP binary--KEGS v0.51 hit an HP linker bug which caused the + executable to not run correctly. (It didn't obey an assembly- + language alignment command correctly). Re-ordering the object + list works around the problem. + +Changes in KEGS v0.51 since v0.50 (6/1/99) +- Fixed many bugs that crept into scanline interrupts over the last few months. +- RAM size is now settable on the commandline: -mem 0x400000 will use + a 4MB expansion RAM card (giving you 4.25MB of memory with ROM 01). +- VBL time used to be a variable (which was wrong)--it's now always the + same number of cycles. +- Typo preventing joystick_driver.c from compiling fixed. +- Auto senses X visual depth, searching for 8 bit, then 15 bit, then 24, + then 16 bit visuals. Can still override this with commandline. + +Changes in KEGS v0.50 since v0.49 (5/31/99) +- Added Linux joystick support with code provided by Jonathan Stark. + Activate with "-joystick" command line option. +- Small improvements in s7 device handling. If you have no s7 devices or no + bootable devices, KEGS launches Applesoft. +- Bug fix in scan-line interrupts--they were occurring at the wrong time + previously. +- Rewrote double-hires color routines. They're still not quite right, + but it's a lot better than it used to be. + +Changes in KEGS v0.49 since v0.48 (5/3/99) +- Fixed a key-repeat bug in v0.48 caused usually with shift-key sequences. +- Fixed bug where GNO would not work with ROM 03. ROM area at $C071-$C07F + is different from ROM 01. +- Ian Schmidt pointed out a special Ensoniq case where an oscillator in + one-shot mode can cause it's partner to start if it is in swap mode. +- Integrated in Geoff Weiss's Solaris x86 ports. I might have broken it + making a few last-minute changes... + +Changes in KEGS v0.48 since v0.47 (4/13/99) +- Even better ADB key repeat--key rollover works more like a real Apple //gs. +- IWM fix: some "smarport" modes were being activated sometimes during + normal 3.5" accesses, resulting in some games not loading correctly. +- Some fixes to serial port emulation to handle programs writing to + the serial port in MIDI mode when the chars will not be consumed. +- Smartport fix to set zero-page locations $42-$47, needed by some poorly- + written game loaders +- The "oscilloscope" effect in some sound-demos now shows the sounds + being played. + +Changes in KEGS v0.47 since v0.46 (4/7/99) +- ADB fix #1: reading $c010 should give key-down status better +- ADB fix #2: key repeat was stopping if modifier key pressed +- ADB fix #3: The game "Pirates" was crashing on startup due to a small bug. +- Bard's Tale 2 was freezing on startup due to a bug in the WAI instruction. +- Major serial port rewrite. Diversi-Tune now runs and sound OK (but there + are some small problems) and serial port emulation is better. + +Changes in KEGS v0.46 since v0.45 (3/21/99) +- Fix for undefined var in engine_c.c. Oops. +- Fix for old bug in engine_c.c causing KEGS to sometimes misinterpret + instructions which cross page boundaries. Was causing Thexder not + to work, at least. + +Changes in KEGS v0.45 since v0.44 (3/20/99) +- Fix for COP instruction in engine_c.c. Pointed out by Kelvin Sherlock. +- Major fixes to Ensoniq emulation, SynthLab sounds much better. +- Fix to iwm.c to deal with corrupt 2IMG archives a little better. + +Changes in KEGS v0.44 since v0.43 (2/23/99) +- -audio 0 option would often cause programs to hang. Bug was that the + audio rate was defaulting to '0' which confused KEGS. +- Made keycode 0x072 be the XK_Break key for XFree86 + +Changes in KEGS v0.43 since v0.42 (2/19/99) +- Support .nib 5.25" format as read-only +- Faster 3.5" nibblization routines (should make startup faster) +- Fixed a very-old 3.5" disk writing bug that made bit-copiers not work + +Changes in KEGS v0.42 since v0.41 (2/1/99) +- Include to fix Linux compile problem +- Fix relative branch timing bug that was making IWM emulation flaky + (backward branches should count as 3 cycles if to the same page, + and 4 if to a different page in emulation mode. Bug always counted + them as 4) +- Gave up on fast 5.25" writes--KEGS always slows to 1MHz for 5.25" + writes since the timing and kludges just got too annoying. +- add "-arate 22050" option to change audio sample rate on the command-line. + Slower audio rates can hit more audio bugs (I'm working on them). +- fixed little-endian bug in smartport.c and partls.c +- fixed side border redraw bug that would sometimes leave super-hires + images on the right-side border. + +Changes in KEGS v0.41 since v0.40 (1/19/99) +- Fixed bug where fill-line mode would not always redraw the screen correctly +- Changed some // comments to /* */ to help David Wilson's Solaris port +- Fixed little-endian bugs in smartport.c preventing mounting of + parititioned disks. Fix submitted by Jonathan Stark. +- Christopher Neufeld noted that fast space/delete option in the control + panel caused KEGS to hit breakpoints. I fixed this and fast arrows and + fast mouse options (they are now just ignored). +- Solaris port by David Wilson now provides a Makefile_solaris + +Changes in KEGS v0.40 since v0.39 (10/25/98) +- 15 and 24 bit depth displays now supported (though somewhat slower than + 8 bit displays). But Super-hires displays now show 256 + simultaneous colors on a 16- or 24-bit X display. + Select a 15-bit display with the cmd line option "-15" and + a 24-bit display with "-24". Otherwise, KEGS defaults to looking + for an 8-bit display, and fails if it cannot find one. +- Some border fixes--border colors now update correctly when palette + changes occur (like via F10). +- Alias F1 to ESC for OS/2. + +Changes in KEGS v0.39 since v0.38 (9/13/98) +- OS/2 port by Tschopp Gilles + - handle cr&lf better in disk_conf + - Drive letters work and are not confused with partition names, so + s7d1 = D:\images\cd:1 will open partition 1 correctly. + - KEGS no longer uses system() to do file copies, it does it all + using POSIX calls. + - Unix-specific socket calls moved from scc.c to scc_driver.h + - Default X handler re-installed properly now for better debug +- Nasty core dump bug found and fixed by Tschopp Gilles in disk switch code + +Changes in KEGS v0.38 since v0.37 (7/28/98) +- IWM bugs: + - fast_disk_emul off under GS/OS caused I/O errors. + KEGS was always slowing down to 1MHz when 5.25" drive was on, when + it should have been obeying the $C036 register. + - bug in IWM on little-endian processors +- disk ejection should now work, but a beta user claimed some bugs on + x86 Linux. +- 2IMG support, but only lightly tested. +- Removed some internal breaks on access to $C0B0 for tool033. +- Modulae also stumbled into some breakpoints by writing to $C02F, + which does nothing. +- Screen refresh simplified (for me) by redrawing the screen while + raster is on first scan-line, rather than line 200. + However, a side effect is some of the graphics during the XMAS DEMO + look a bit choppier. +- More SCC fixes to avoid breakpoints under GNO. +- Start support for sound under Linux, but it sounds horrible right now. + Any Linux sound gurus want to help out? +- Fixed possible array-overrun bug in video.c around border effects. + Maybe shared memory works under x86 Linux now? +- Made changes for OS/2 port to fopen() text files. From Blue Neon. + + +Changes in KEGS v0.37 since v0.36 (7/13/98) +- Linux PPC port completed and functional. KEGS has been tested to + run quite well and quite fast on a 240MHz 604e running + MkLinux pre-DR3. +- Change LITTLE_ENDIAN define to KEGS_LITTLE_ENDIAN since Linux + always defines LITTLE_ENDIAN as a silly macro. +- Dumb bug in IWM 3.5" routines could cause core dumps if disk arm moved + from outer track to inner track very quickly. +- Deleted some breakpoints that some Second Sight searching code would hit. +- Ignore some SCC reset commands GNO would use that caused KEGS to stop. +- Handle odd partitions better--some //gs formatted Zips had a blocksize + of 0, which defaults to 512 now. +- Handle some keysyms better to avoid MkLinux bug with keysym 0. + +Changes in KEGS v0.36 since v0.35 (5/30/98) + +- Linux x86 port completed and functional with help from Karl Pfleger +- Linux clock fixes--should handle daylight savings better on Linux +- LITTLE_ENDIAN defines +- Start making fixes for NeXTStep due to Eric Sunshine +- Fixed bug in HP asm code with I/O fetches--caused //gs selftests to fail + and a bug in scc.c was also causing self-tests to fail. + +Changes in KEGS v0.35 since v0.34 (5/17/98) + +- engine_c.c fully implemented--KEGS now has a version completely written + in C, and now portable to other Unix machines. +- KEGS got another 5% faster with more tweaks to the asm dispatch loop. + +Changes in KEGS v0.34 since v0.33 + +- KEGS is 10-15% faster due to finally implementing a planned recoding + of the dispatch loop. + +Changes in KEGS v0.33 since v0.32 (5/7/98) + +- Fixed bug in engine_s.s that prevented compiling on pre-10.20 systems. +- ADB mouse interrupts work now. Fixed "bug" where GSHK would think + mouse button was depressed at startup. (GS/OS is looking at mouse + button 1 status, which accidentally was reading as down). +- ADB emulation of read char_sets and read_kbd_layouts now matches a real + //gs. +- optimization to allow dereferencing page_info[] even if BANK_IO is set, + to get a small speed improvement in engines_s:dispatch(). +- SCC logs are 'Z' at the disas prompt. +- Tool decoded is 'T' at the disas prompt. +- SCC changes to support slot 1 == port 6501 and slot 2 == port 6502, + with limited interrupt support. Most serial tasks won't work still, + but some do. PR#1/2 and IN#1/2 work fine. getty under GNO doesn't. +- -audio [0/1] forces audio off/on. This just stops the sound playing-- + internally all Ensoniq interrupts/etc are fully emulated. If display + is not using shared memory (i.e., it's remote), audio defaults to off. + (but can be forced on with -audio 1). +- -display {foo} sends X display to {foo}. + +Changes in KEGS v0.32 since v0.31 (10/23/97) + +- Faster dispatch loop, for a 10-15% overall performance improvement +- Fixed sound bug where Oversampler would make KEGS halt (Oversampler + said turn on 128 oscillators, and KEGS tried to...) +- Fixed bug where KEGS would not work on 24-bit displays due to a typo. +- Added frame skipping support (-skip n) and auto frame skipping if you + are not using shared memory (like displaying KEGS to a remote machine). +- Added -noshm support for forcing off shared memory, so you can see how + much it helps. + +Changes in KEGS v0.31 since v0.30 (9/23/97) + +- New mouse handling--Press F8 to hide X windows cursor and constrain + cursor inside window. Makes using the mouse much easier. + F8 toggles back to normal. +- Add revision to status area. +- Remove "slow memory" calculation. KEGS was emulating slowing down to + 1MHz to write to slow memory (bank $E0 or $E1). But true //gs + accelerators have a smarter trick, so I just removed it from + KEGS. KEGS still slows down for I/O reads and writes. + This eliminates the confusing 40MHz speed numbers you'd sometimes get. + KEGS can also now run faster when it would have slowed down to + 1MHz before. +- Turn off accurate IWM emulation be default, for much faster emulation. + Bit copiers won't work by default now. Toggle accurate IWM + with F7. Accurate IWM forces 1MHz speed for 5.25" and 2.5MHz for + 3.5", but less accurate IWM runs as fast as possible. +- Add optional size to s7dx entries in disk_conf, to allow using /dev/rfloppy. +- Allow mounting partitions by number, instead of just by name, since some + Mac-formatted Zip disks don't have partition names. +- Add -ignbadacc to ignore bad memory accesses. +- Increase MAX_C030_TIMES. Otherwise, fast workstations could generate too + many clicks per VBL, causing an assertion to fail. +- Small speed increase detecting changes in the superhires screen. +- Alt_L is now Open-Apple, and Alt_R is Closed-Apple. +- KEGS now uses just one private colormap, so xwd can get screendumps. + + diff --git a/KEGSMAC.app/Contents/Info.plist b/KEGSMAC.app/Contents/Info.plist new file mode 100644 index 0000000..15a616a --- /dev/null +++ b/KEGSMAC.app/Contents/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + KEGSMAC + CFBundleIconFile + kegsicon.icns + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 0.1 + CSResourcesFileMapped + + + diff --git a/KEGSMAC.app/Contents/MacOS/KEGSMAC b/KEGSMAC.app/Contents/MacOS/KEGSMAC new file mode 100755 index 0000000..81fafe8 Binary files /dev/null and b/KEGSMAC.app/Contents/MacOS/KEGSMAC differ diff --git a/KEGSMAC.app/Contents/PkgInfo b/KEGSMAC.app/Contents/PkgInfo new file mode 100644 index 0000000..6f749b0 --- /dev/null +++ b/KEGSMAC.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? diff --git a/KEGSMAC.app/Contents/Resources/English.lproj/InfoPlist.strings b/KEGSMAC.app/Contents/Resources/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..036ca1e Binary files /dev/null and b/KEGSMAC.app/Contents/Resources/English.lproj/InfoPlist.strings differ diff --git a/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/classes.nib b/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/classes.nib new file mode 100755 index 0000000..ea58db1 --- /dev/null +++ b/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/classes.nib @@ -0,0 +1,4 @@ +{ +IBClasses = (); +IBVersion = 1; +} diff --git a/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/info.nib b/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/info.nib new file mode 100644 index 0000000..4fcb7b8 --- /dev/null +++ b/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/info.nib @@ -0,0 +1,19 @@ + + + + + IBDocumentLocation + 152 85 356 240 0 0 1280 832 + IBEditorPositions + + 29 + 69 252 182 44 0 0 1280 832 + + IBFramework Version + 291.0 + IBSystem Version + 6R73 + targetFramework + IBCarbonFramework + + diff --git a/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/objects.xib b/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/objects.xib new file mode 100644 index 0000000..616ea10 --- /dev/null +++ b/KEGSMAC.app/Contents/Resources/English.lproj/main.nib/objects.xib @@ -0,0 +1,169 @@ + + + IBCarbonFramework + + NSApplication + + + + main + + + KEGSMAC + + KEGSMAC + + + About KEGSMAC + 0 + abou + + + TRUE + + + Quit + 0 + quit + + + _NSAppleMenu + + + + File + + File + + + Configuration F4 + 0 + KCFG + Enter KEGS Configuration Panel + + + + + + Window + + Window + + + Zoom Window + zoom + + + TRUE + Minimize Window + 0 + mini + + + TRUE + Minimize All Windows + 0 + mina + + + TRUE + + + TRUE + Bring All to Front + bfrt + + + TRUE + Arrange in Front + 1572864 + frnt + + + _NSWindowsMenu + + + + _NSMainMenu + + + + + Window + + Window + + + TRUE + Minimize Window + m + mini + + + TRUE + Minimize All Windows + m + 1572864 + mini + + + TRUE + + + TRUE + Bring All to Front + frnt + + + TRUE + Bring in Front + 1572864 + frnt + + + _NSWindowsMenu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Files Owner + + MenuBar + + + 201 + diff --git a/KEGSMAC.app/Contents/Resources/kegsicon.icns b/KEGSMAC.app/Contents/Resources/kegsicon.icns new file mode 100644 index 0000000..72ea172 Binary files /dev/null and b/KEGSMAC.app/Contents/Resources/kegsicon.icns differ diff --git a/KEGSMAC.app/Icon? b/KEGSMAC.app/Icon? new file mode 100644 index 0000000..e69de29 diff --git a/README.compile b/README.compile new file mode 100644 index 0000000..1563e6f --- /dev/null +++ b/README.compile @@ -0,0 +1,113 @@ + +NOTE: The build process changed as of KEGS v0.70! + +General build instructions: +-------------------------- + +You need to build with a make utility. I've only tested GNU make. +There's a default Makefile, which should work for nearly any environment. +The Makefile includes a file called "vars" which defines the platform- +dependent variables. You need to make vars point to the appropriate +file for your machine. + +This makes my maintenance of the diverse platforms a bit easier. + +WIN32 build instructions: +------------------------ + +See the file README.win32 for build instructions and other information +for Microsoft Windows. + + +Mac OS X build instructions (the default): +------------------------------------------ + +KEGS is easy to compile. Just cd to the src directory and type "make". +KEGS requires perl to be in your path (or just edit the vars file to give +the full path to wherever you installed perl). Perl version 4 or 5 is +fine. + +After the "make" has finished, it will create the application KEGSMAC. + +To run, see README.mac. + +X86 Linux build instructions: +---------------------------- + +Use the vars_x86linux file with: + +rm vars; ln -s vars_x86linux vars +make + +KEGS assumes perl is in your path. If it is somewhere else, you need to edit +the "PERL = perl" line in the vars file and make it point to the correct place. + +For audio, KEGS needs access to /dev/dsp. If the permissions do not allow +KEGS to access /dev/dsp, it can fail with a cryptic error message. As root, +just do: "chmod 666 /dev/dsp". + + +PowerPC Linux build instructions: +---------------------------- + +Use the vars_linuxppc vars file by: + +rm vars; ln -s vars_linuxppc vars +make + +KEGS assumes perl is in your path. If it is somewhere else, you need to edit +the "PERL = perl" line in the vars file and make it point to the correct place. + +Audio is currently disabled by default, but you can try turning it on +by runnning "kegs -audio 1". It sounds horrible to me, but sounds do +come out. + +Solaris SPARC build instructions: +-------------------------------- + +Use the vars_solaris vars file by: + +rm vars; ln -s vars_solaris vars +make + +KEGS assumes perl is in your path. If it is somewhere else, you need to edit +the "PERL = perl" line in the vars file and make it point to the correct place. + +Audio is currently disabled by default, but you can try turning it on +by runnning "kegs -audio 1". + +Solaris x86 build instructions: +-------------------------------- + +Use the vars_x86solaris vars file by: + +rm vars; ln -s vars_x86solaris vars +make + +KEGS assumes perl is in your path. If it is somewhere else, you need to edit +the "PERL = perl" line in the vars file and make it point to the correct place. + +Audio is currently disabled by default, but you can try turning it on +by runnning "kegs -audio 1". + +HP-UX assembly-emulation instructions: +------------------------------------- + +Use the vars_hp vars file by: + +rm vars; ln -s vars_hp vars + +Edit the Makefile, and remove "engine_c.o" from the "OBJECTS1=" line at +the top. Then just type "make". + + +Other platform "C" build instructions: +------------------------------------- + +I don't know--you tell me. If you are porting to an X-windows and +Unix-based machine, it should be easy. Start with vars_x86linux if +you are a little-endian machine, or vars_linuxppc if you are big +endian. Don't define -DKEGS_LITTLE_ENDIAN unless your processor is +little-endian (x86, Alpha). Mac, Sun, MIPS, HP, Motorola, and IBM are +big-endian. + diff --git a/README.kegs b/README.kegs new file mode 100644 index 0000000..379968b --- /dev/null +++ b/README.kegs @@ -0,0 +1,989 @@ + +KEGS: Kent's Emulated GS version 0.86 +http://kegs.sourceforge.net/ + +What is this? +------------- + +KEGS is an Apple IIgs emulator for Mac OS X, Linux, and Win32. +The Apple IIgs was the last released computer in the Apple II line. +It first was sold in 1986. + +KEGS supports all Apple IIgs graphics modes (which include all Apple //e +modes), plus plays all Apple IIgs sounds accurately. It supports +limited serial port emulation through sockets, or can use real serial ports +on Windows and Mac OS X. + +The ROMs and GS/OS (the Apple IIgs operating system) are not included +with KEGS since they are not freely distributable. KEGS is a little +user-hostile now, so if something doesn't work, let me know what went +wrong, and I'll try to help you out. See my email address at the end of +this file. + +KEGS features: +------------- + +Fast 65816 emulation: + About 80MHz on a P4 1.7GHz or a G4 1GHz. +Emulates low-level 5.25" and 3.5" drive accesses (even nibble-copiers work!). +Emulates classic Apple II sound and 32-voice Ensoniq sound. + All sound is played in 16-bit stereo at 48KHz (44100 on a Mac). +Emulates all Apple IIgs graphics modes, including border effects. + Can handle mixed-displays (superhires at the top, lores at the bottom). + Always does 60 full screen video updates per second. + Even supports 3200-color pictures. +Mouse and joystick support. +Emulates all Apple IIgs memory "tricks" for full compatibility. +Low-level ADB keyboard and mouse emulation enables Wolfenstein 3D to run. +Clock chip emulation makes the host time available to the Apple IIgs. +Emulated battery RAM remembers control panel settings. +Limited SCC (serial port) emulation to enable PR#1/2 IN#1/2 and other + serial programs to work. + +KEGS by default emulates a 8MB Apple IIgs, but you can change this with +the "-mem" command line option. + +KEGS is so accurate, even the built-in ROM selftests pass (you must be in +2.8MHz speed mode to pass the self-tests). + +Release info: +------------ + +Included files: + CHANGES - Description of changes since last release + README.kegs - you're here + README.compile - Describes how to build KEGS + README.linux.rpm - Describes how to install KEGS's RPM for Linux + README.win32 - Win32 special directions + README.mac - Mac OS X special directions + INTERNALS.overview - description of how KEGS code works + INTERNALS.xdriver - Describes the xdriver.c routines for porting + INTERNALS.iwm - Describes the internal 3.5" and 5.25" disk + handling routines + kegs - the executable, for HP-UX 10.20+ + kegs.spec - The Linux spec file for making an RPM + kegs_conf - disk image configuration info + to_pro - Hard-to-use ProDOS volume creator + partls - Lists partitions on Apple-partitioned hard + drives or CD-ROMs + src/ - All the source code, with a Makefile + +You need to provide: + + 1) Patience. + 2) a ROM file called "ROM", "ROM.01" or "ROM.03" in the KEGS directory. + It can be either from a ROM 01 (131072 bytes long) or from a + ROM 03 machine (262144 bytes long.) + 3) A disk image to boot. This can be either "raw" format or 2IMG. + See discussion below. GS/OS would be best. + +Getting ROMs +------------ + +You need a copy of the memory from fe/0000 - ff/ffff from a ROM 01 GS +or fc/0000 - ff/ffff from a ROM 03 GS, and put that in a file called +"ROM". I'll eventually write detailed instructions on how to do this. + +Running KEGS: +------------ + +The distribution comes in 3 parts: a source-only distribution (kegs.xxx.tar.gz), +along with two binary distributions for Mac and Windows. + +See the README.compile file for more info about compiling for Linux. + +On all platforms except the Mac, you must start KEGS from a terminal +window. KEGS will open a new window and use the window you started it from +as a "debug" window. + +On a MAC, you need to place the "config.kegs" file someplace where KEGS +can find it. The simplest place is in your home directory, so copy it there +with the Finder (or using the Terminal). + +Start kegs by Double-clicking the KEGSMAC icon on a MAC, or by running +the executable (kegswin on Windows, and kegs on Linux). KEGSMAC can +be run by the Terminal window as well (which enables access to more debug +information) by typing: "./KEGSMAC.app/Contents/MacOS/KEGSMAC". + +Assuming all goes well, KEGS will then boot up but probably not find any +disk images. See below for how to tell KEGS what disk images to use. +Tip: Hitting "F8" locks the mouse in the window (and hides the host cursor) +until you hit "F8" again. + +Disk Images: +----------- + +You tell KEGS what disk images to use through the Configuration panel. + +You enter the Configuration panel by pressing F4 at any time. Then select, +"Disk Configuration". Each slot and drive that can be loaded with an image +is listed. "s5d1" means slot 5, drive 1. Slot 5 devices are 3.5" 800K disks, +and slot 6 devices are 5.25" 140K disks. Slot 7 devices are virtual hard +drives, and can be any size at all (although ProDOS-formatted drives +should be less than 32MB). + +Just use the arrow keys to navigate to the device entry to change, +and then select it by pressing Return. A scrollable file selection +interface is presented, letting you located your image files. To +save navigation, you can press Tab to toggle between entering a path +manually, and using the selector. Press Return on ".." entries to go up +a directory level. When you find the image you want, just press Return. + +If the image has partitions that KEGS supports, another selection +dialog will have you select which partition to mount. You will probably +only have partitions on direct devices you mount. For instance, on a +Mac, /dev/disk1 is usually the CDROM drive. + +KEGS can handle "raw", .dsk, .po, 2IMG, 5.25" ".nib" images, some Mac +Diskcopy images and partitioned images. The .dsk and .po formats you often +find on the web are really "raw" formats, and so they work fine. KEGS uses +the host file permissions to encode the read/write status of the image. + +An image is the representation of an Apple IIgs disk, but in a file on +your computer. For 3.5" disks, for example, a raw image would be exactly +800K bytes long (819200 bytes). KEGS intercepts the emulated GS accesses to +the image, and does the correct reads and writes of the Unix file instead. + +To do "useful" things with KEGS, you need to get a bootable disk image. +You can go to http://www.info.apple.com/support/oldersoftwarelist.html and +get Apple IIgs System 6. Unfortunately, Apple now only has .sea files which +are executable files for Macintosh only. You need a macintosh to execute +those programs, which creates Disk Copy image files with no special extensions +(and with spaces in the names). Once you get those files back to your +host machine, you can use them by listing them in kegs_conf. + +KEGS also supports partitioned devices. For instance, if you have a CD-ROM +on your computer, just pop an Apple II CD in, and KEGS can mount it, if +you have a Unix-base system (Linux, any Unix, and Mac OS X). + +If you're on a Mac, be careful letting KEGS use your HFS partitions-- +GSOS has many HFS bugs when it is writing. + +If you do not have any disk mounted in s7d1, KEGS will jump into BASIC. + +Support for 5.25" nibblized images is read-only for now (since the +format is kinda simplistic, it's tricky for KEGS to write to it). +Just mount your image, like "disk.nib" in the kegs_conf file like +any .dsk or .po image. + + +Key summary: +----------- + +F1: Alias of Command +F2: Alias of Option +F3: Alias of ESC for OS/2 compatibility. +F4: Configuration Panel +F6: Toggle through the 4 speeds: Unlimited, 1MHz, 2.8MHz, 8.0MHz +Shift-F6: Enter KEGS debugger +F7: Toggle fast_disk_emul on/off +F8: Toggle pointer hiding on/off. +F9: Invert the sense of the joystick. +Shift-F9: Swap x and y joystick/paddle axes. +F10: Attempt to change the a2vid_palette (only useful on 8-bit color display) +F11: Full screen mode (does not do anything yet). +F12: Alias of Pause/Break which is treated as Reset + +F2, Alt_R, Meta_r, Menu, Print, Mode_switch, Option: Option key +F1, Alt_L, Meta_L, Cancel, Scroll_lock, Command: Command key +Num_Lock: Keypad "Clear". +F12, Pause, Break: Reset + +"Home": Alias for "=" on the keypad (since my Unix keyboard doesn't have an =). + +Using KEGS: +---------- + +The host computer mouse is the Apple IIgs mouse and joystick by default. +By default, the host pointer is not constrained inside the window and +remains visible. Press F8 to hide the cursor and constrain the mouse. F8 +again toggles out of constrain mode. When the GSOS desktop is running, +KEGS hides the host cursor automatically and enables special tracking +which forces the emulated cursor to follow the host cursor. If this doesn't +work right under some program, just press F8 for better compatibility. + +The default joystick is the mouse position. Upper left is 0,0. Lower right +is 255,255. Press Shift-F9 to swap the X and Y axes. Press F9 to reverse +the sense of both paddles (so 0 becomes 255, etc). Swapping and +reversing are convenient with paddle-based games like "Little Brick Out" +so that the mouse will be moving like the paddle on the screen. "Little +Brick Out" is on the DOS 3.3 master disk. The joystick does not work +properly if the pointer is constrained in the window. + +If you have a real joystick on Linux, start KEGS with "-joystick" and +you should be able to use it. Real joysticks should also work on Windows. + +The left mouse button is the mouse button for KEGS. The right mouse +button (if you have it) or F6 toggles between four speed modes. Mode 0 +(the default) means run as fast as possible. Mode 1 means run at 1MHz. +Mode 2 means run at 2.8MHz. Mode 3 means run at 8.0MHz (about the speed +of a ZipGS accelerator). Most Apple //e (or earlier) games need to be +run at 1MHz. Many Apple IIgs demos must run at 2.8MHz or they crash. Try +running ornery programs at 2.8MHz. 3200 pictures generally only display +correctly at 2.8MHz or sometimes 8.0MHz. + +The middle mouse button or Shift-F6 causes KEGS to stop emulation, and enter +the debugger. You can continue with "g" then return in the debug window. +You can also disassemble memory, etc. The section "Debugging KEGS" +above describes the debugger interface a little more. + +KEGS has no pop-up menus or other interactive interfaces (other than +the debug window). Input to the debug window is only acted upon when +the emulation is stopped by hitting a breakpoint or pressing the right-most +mouse button. + +Quitting KEGS: +------------- + +Just close the main KEGS window, and KEGS will exit cleanly. Or you +can select Quit from the menu. Or enter ctrl-c in the debugger window. +Or press the middle-mouse button in the emulation window, and then type +"q" return in the debug window. + + +Debugging KEGS: +-------------- + +KEGS by default now continues emulation even when it detects buggy programs +running. (Now I know why Appleworks GS always seemed to crash!). + +KEGS divides buggy programs into two severities: Code Yellow and Code Red. +The status is displayed in words in the text area under the emulation window. +If nothing's wrong, nothing is printed. + +A Yellow bug is a mild bug where an Apple IIgs program merely read an +invalid location. Although completely harmless, it indicates the potential +for some Apple IIgs program bug which may become more severe shortly. +For instance, closing the "About This Apple IIgs" window in the Finder +causes a code yellow alert, but it seems quite harmless. + +A Code Red bug is a more serious problem. The Apple IIgs program either +tried to write non-existent memory, entered an invalid system state, or +perhaps just tried to use an Apple IIgs feature which KEGS does not implement +yet. Note that entering GSBUG tends to cause a Code Red alert always, so if +you intended to enter it, you can ignore it. My recommendation is to +save work immediately (to new files) and restart KEGS if you get into the +Red mode. + +KEGS also supports breakpoints and watchpoints. In the debug window, you +set a breakpoint at an address by typing the address, followed by a 'B' +(it must be in caps). To set a breakpoint on the interrupt jump point, +type: + +e1/0010B + +To list all breakpoints, just type 'B' with no number in front of it. +To delete a breakpoint, enter its address followed by 'D', so + +e1/0010D + +deletes the above breakpoint. The addresses work like the IIgs monitor: +once you change banks, you can use shortcut addresses: + +e1/0010B +14B + +will add breakpoints at e1/0010 and e1/0014. + +This is a "transparent" breakpoint--memory is not changed. But any +read or write to that address will cause KEGS to halt. So you can +set breakpoints on I/O addresses, or ROM, or whatever. Setting a breakpoint +slows KEGS down somewhat, but only on accesses to the 256 byte "page" +the breakpoint is on. Breakpoints are not just instruction breakpoints, +they also cause KEGS to halt on any data access, too (usually called +watchpoints). + +Frederic Devernay has written a nice help screen available in the +debugger when you type "h". + +KEGS command-line option summary: +-------------------------------- + +-mem {mem_amt}: KEGS will use mem_amt as the amount of expansion RAM in + the IIgs. This memory is in addition to the 256KB on a ROM 01 + motherboard, or 1MB on a ROM 03. The memory is in bytes, + and it will be rounded down to the nearest 64KB. "-mem 0x800000" + will use 8MB of expansion RAM (the default). +-badrd: Causes KEGS to halt on any access to invalid memory addresses. + Useful for debugging. By default, KEGS allows reads to invalid + memory since the Finder does some (especially when you open the + About window, and then close it). But KEGS warns you about these + accesses in the debug window. In general, these warnings + indicate buggy programs. If the warnings get severe, it's + a good sign you should quit KEGS and start over before the + emulated program crashes. -badrd would be the default for KEGS + if it wasn't for the Finder's About window's problem. +-ignbadacc: Causes KEGS to allow reads & writes to invalid memory + addresses without printing any warnings. Useful for running + extremely buggy programs so you don't have to see all the warning + messages scroll by. +-skip: KEGS will "skip" that many screen redraws between refreshes. + -skip 0 will do 60 frames per second, -skip 1 will do 30 fps, + -skip 5 will do 10 fps. +-audio [0/1]: Forces audio [off/on]. By default, audio is on unless + the X display is a remote machine or shared memory is off. + This switch can override the default. -audio 0 causes KEGS to + not fork the background audio process, but Ensoniq emulation + is still 100% accurate, just the sound is not sent to the + workstation speaker. Audio defaults off on Linux for now. +-arate {num}: Forces audio sample rate to {num}. 44100 and 48000 are + usual, you can try 22050 to reduce KEGS's overhead. On a reasonably + fast machine (>250MHz or so), you shouldn't need to mess with this. +-dhr140: Will use the old Double-hires color algorithm that results in + exactly 140 colors across the screen, as opposed to the blending + being done by default. + +X-Windows/Linux options +-15: KEGS will only look for a 15-bit X-Window display. +-16: KEGS will only look for a 16-bit X-Window display (not tested, probably + will get red colors wrong). +-24: KEGS will only look for a 24-bit X-Window display. +-display {machine:0.0}: Same as setting the environment variable DISPLAY. + Sends X display to {machine:0.0}. +-joystick: Will use /dev/js0 as the joystick. +-noshm: KEGS will not try to used shared memory for the X graphics display. + This will make KEGS much slower on graphics-intensive tasks, + by as much as a factor of 10! By default, -noshm causes an + effective -skip of 3 which is 15 fps. You can override this + default by specifying a -skip explicitly. + + +Command/Option keys: +------------------- + +If you have a workstation keyboard with the new Windows keys, you can +use them as the command/option keys. This is what I use. Since many people +don't have the PC keyboard, there are several alternatives. + +The following keys are Option (closed-apple) (not all keyboards have all +keys): F2, Meta_R, Alt_R, Cancel, Print_screen, Mode_switch, Option, +or the Windows key just to the right of the spacebar. The following keys are +Command (open-apple): F1, Meta_L, Alt_L, Menu, Scroll_lock, Command, +the Windows key left of the spacebar, and the Windows key on the far right +that looks like a pull-down menu. You can use F1 and F2 if you cannot make +anything else work. + +If you can't get any of these to work on your machine, let me know. +Note that X Windows often has other things mapped to Meta- and Alt- +key sequences, so they often don't get passed through to KEGS. So it's +best to use another key instead of Alt or Meta. + +The joystick/paddle buttons are just the Command and Option keys. + +Reset: +----- + +The reset key is Pause/Break or F12. You must hit it with Ctrl to get it to +take effect (just like a real Apple IIgs). Ctrl-Command-Reset +forces a reboot. Ctrl-Command-Option-Reset enters selftests. +Selftests will pass if you force speed to 2.8MHz using the middle +button. Watch out for ctrl-shift-Break--it will likely kill your +X Windows session. + +Control Panel: +------------- + +You can get to the Apple IIgs control panel (unless some application +has locked it out) using Ctrl-Command-ESC. + + +How to use "to_pro": +------------------- + +This lame utility serves two purposes: It "formats" large disk images, +and lets you move files from Unix into the simulator. It does this +by taking the files you provide, and putting them onto Unix file called +"POOF1" that is an image in ProDOS format. + +So, if you have a wolfdemo.bxy file from an FTP site, you can get it +into the emulator by: + +to_pro -800 wolfdemo.bxy + +which creates an 800K Unix file called "POOF1". POOF1 is now an +image that can be loaded into KEGS, and when you catalog it, it will +have wolfdemo.bxy on it. + +To create a 4MB image: + +to_pro -4096 wolfdemo.bxy + +which puts wolfdemo.bxy on a much larger image. + +I don't know what happens if the file, wolfdemo.bxy, is bigger than +the image...it probably crashes. + +Even if you want to format a "blank" image, you have to put something in it. +Like: + +echo "This is a lame utility" > foo +to_pro -16384 foo + +...creates a 16MB POOF1 with the file foo on it. Just delete foo +from within KEGS. + +See? I told you it was a lame utility! + +to_pro can handle up to 51 files at a time--for example: + +to_pro -32000 *.shk + +...would put all *.shk files in the current Unix directory into a 31.25MB +image called POOF1. + +To_pro tries to truncate Unix filenames to the 15 character ProDOS +limit, and converts all punctuation to dots. I've tested it enough +that it has worked for my purposes. + +The algorithm to_pro uses to create a disk volume is possibly suspect. +I recommend reformatting any images again inside KEGS (using GS/OS, for +instance) just to make sure the directory structure is good. To_pro +is intended to put files into images quickly and easily, and then to +copy the files off of those images onto images formatted from within +KEGS by an Apple IIgs OS. + +Since ProDOS cannot handle > 32MB images, make sure you run to_pro with +arguments under 32767. I personally haven't tried a partition bigger +than 30000K (about 2.5MB short of the maximum). Well, you can use bigger +images if you format them HFS, but I don't trust the GS/OS HFS driver. + +To_pro automatically sets the ProDOS filetype of files ending in ".shk" +to $E0. + +Details on config.kegs and disk images +-------------------------------------- + +The file "config.kegs" describes the images KEGS will use. The sample +file has all the lines commented out with '#' to show sample uses. +Remember, KEGS will boot s7d1 (unless you've changed that using the +Apple IIgs control panel), so you must put an image in that slot. + +Changing disks in slot 7 does not work, but you can move around +disks in slots 5 and 6. This allows you to "eject" disks and change them. +This is especially useful for multi-disk 5.25" programs. + +KEGS uses the Unix permissions on raw disk images to decide how to load +it into the emulator. If the file is unreadable, it cannot load the +image (duh). + +KEGS, by default, runs the IWM (3.5" and 5.25" disks) emulation in an +"approximate" mode, called "fast_disk_emul". In this mode, KEGS +emulates the hardware "faster" than real, meaning the data the code +being emulated expects is made available much faster than on a real +Apple IIgs, providing a nice speed boost. For instance, the 5.25" +drives run 10x the real speed usually. Almost everything will work +except for nibble copiers, which don't like the data coming this fast. +(Meaning, unless you're using a nibble copier, you shouldn't run into an +issue. All games/demos/etc run fine in this mode). To make nibble +copiers work, Press F7. + +KEGS can read in the ".nib" nibblized disk format, but as read-only mode. If +the emulated image is no longer ProDOS or DOS 3.3 standard, KEGS will +automatically treat the image as "Not-write-through-to-Image" from then +on. This mode means KEGS will continue to emulate the disk properly in +memory, but it cannot encode the changes in the standard .dsk or .nib +image format. It prints a message saying it has done so. However, +the "disk" in emulation is fully useable as long as KEGS is running. A +standard reformatting will not cause an image to flip to not-write- +through-to-Image, but running things like a "drive-speed" test will cause +further changes not to propagate to the Unix file. You will need +to "eject" the image and re-insert it before writes will take effect. + +In full accuracy mode (i.e., not fast_disk_emul), 5.25" drive accesses +force KEGS to run at 1MHz, and 3.5" drive accesses force KEGS to run at +2.5MHz. + +KEGS Timing: +----------- + +KEGS supports running at four speeds: 1MHz, 2.8MHz, 8.0MHz, and Unlimited. +Pressing the middle mouse button cycles between these modes. The 1MHz +and 2.8MHz speeds force KEGS to run at exactly those speeds, providing +accurate reproduction of a real Apple IIgs. + +KEGS will always run at 1MHz at least. If it is unable to keep up, +it will extend the emulated time to maintain the illusion of running +at 1MHz. That is, it may do just 40 screen refreshes per real second, +instead of the usual 60. This happens rarely. + +If you force KEGS to run at 1MHz, it will strive to run at exactly +1MHz (well, really 1.024MHz). If it is running faster (almost always), +it will pause briefly several times a second to maintain the 1MHz speed. It +does this in a friendly way that makes time available to other tasks. +This makes older Apple II games very playable just like a +real Apple IIgs on slow speed. KEGS is running at exactly the same +speed as an Apple //e when in 1MHz mode. The 1MHz mode you set +through the right mouse button overrides the "fast" mode you can access +through the control panel. But, 3.5" accesses will "speed up" to 2.8MHz +to enable that code to operate correctly while the 3.5" disk is being +accessed. + +If you force KEGS to run at 2.8MHz, KEGS tries to run at exactly 2.8MHz. But +like a real unaccelerated Apple IIgs, if you set the control panel to +"slow", it will really be running at 1MHz. Accesses to 5.25" disk +automatically slow down to 1MHz, when running the IWM in accurate +mode (F7). KEGS may not be able to keep up with some programs running +at 2.8MHz due to video and sound overheads on lower-end machines. If +that happens, it effectively runs slower by extending the emulated +"second", like in the 1MHz mode. You can tell this is happening +when Eff MHz in the status area falls below 2.5MHz. If KEGS is running +faster than 2.8MHz, it takes small pauses to slow down, just like in +1MHz. Many Apple IIgs demos must be run at 2.8MHz. The built-in +selftests (cmd-option-ctrl-Reset) must run at 2.8MHz. Many Apple IIgs +action games are more playable at 2.8MHz. + +The 8.0MHz setting means follow the ZipGS-selected speed, but don't go +faster than 8.0MHz. If your host computer cannot keep up, then the +emulated second will be extended. You can use the ZipGS control panel, +or ZIPPY.GS on the sample disk image to set the emulated ZipGS speed to +anything from 1MHz to 8MHz in .5MHz increments. + +The Unlimited setting means run as fast as possible, whatever speed that +is (but always above 1MHz). Eff MHz gives you the current Apple IIgs +equivalent speed. Many games will be unplayable at the unlimited +setting. Setting the IIgs control panel speed to "slow" will slow down +to 1MHz. + +Sound output has an interesting relationship to KEGS timing. KEGS must +play one second of sound per second of emulated time. Normally, this +works out exactly right. But as noted above, if KEGS can't maintain the +needed speed, it extends the emulated second. If it extends the second +to 1.4 real seconds, that means KEGS only produces 1.0 second of sound +data every 1.4 seconds--the sound breaks up! + +In all cases, 1MHz to KEGS is 1.024MHz. And 2.8MHz to KEGS is 2.52MHz +(trying to approximate the slowdown causes by memory refresh on a real +Apple IIgs). It's just easier to say 1MHz and 2.8MHz. + + +KEGS SAMPLE_DISK: +---------------- + +I'm providing a sample disk of freely available utilities/programs to +demonstrate a little of what KEGS can do. I'm also including my simple +changes to a benchmark called "SPEEDTEST" to make it run under ProDOS and +time itself automatically. The SAMPLE_DISK is not bootable since I'm +not sure if I can distribute PRODOS (the OS). + + + SPEEDTEST: + --------- + +In the folder "SPEEDTEST", there are two BASIC programs. OLD.SPEEDTEST +is the old, unmodified DOS 3.3 emulator benchmark by Clayten Hamacher. +It does not run properly under ProDOS 8. My modified version is +SPEED.PRO, meaning converted to ProDOS. I made few modifications, other +than to make the benchmarks time themselves. + +To run, just say "RUN SPEED.PRO". To run benchmarks, press "B". If +you say "A)ll tests", make sure you have a 5.25" disk image in s6d1! +(A blank 140K image will work fine). + +This modified SPEED.PRO can run on ANY Apple IIgs emulator (or on the real +thing). + + GSOS7, GSOS5, BYE.SYSTEM: + ------------------------ + +These are handy utilities I use on my s7d1 boot disk. Get a GS/OS 6.x +bootable disk image. (See GSOS.INFO file for how to get GS/OS). +Remove "PRODOS" from that disk's root directory, and copy GSOS7 to +the root directory. Then copy SYSTEM/P8 to PRODOS. Then move +BASIC.System into SYSTEM/. Then copy BYE.SYSTEM to the root directory, +then move BASIC.SYSTEM back to the root directory. + +What all this means is that now the root directory of your system disk +is: GSOS7, (other stuff), PRODOS, BYE.SYSTEM, and BASIC.SYSTEM. +When you boot, ProDOS will boot (this is PRODOS 8) and will search +for the first *.SYSTEM file, and run it. BYE.SYSTEM just does a BYE +command, which puts you in the PRODOS 8 textual launcher. +If you now select GSOS7 (the first entry, already highlighted, just +hit return), it will boot GSOS on slot 7. (Use GSOS5 to boot slot5). +Or, just move down and select BASIC.SYSTEM to go to BASIC. A very simple +program launcher!? + +Note that I didn't write GSOS5 or GSOS7--I just made a one byte hack +to the default GS/OS launcher. No real wizardry is going on here. + + + SHRINKIT3.4, GSHK1.1: + -------------------- + +Useful for unpacking .SHK files you can download off of the net. +Always use GSHK (GS/OS version of ShrinkIt) for GS programs since +they may have resource forks. It's also faster. GSHK must be run from GS/OS. + + LISTV2.0: + -------- + +ProDOS 8 text file lister, useful for viewing text files. + + Wolfenstein3D: + ------ + +Wolfenstein 3D for the Apple IIgs. No kidding! Must be run from GS/OS. + + SOUND22: + ------- + +Cool little ProDOS 8 program (SOUND.EDITOR) that plays hi-fidelity +(relatively) through the old Apple II speaker. This is included as a +demonstration of how accurate KEGS sound emulation is. + + Sound.Smith.95: + -------------- + +GS/OS application that plays SoundSmith songs, which are spreadsheet music, +like MODs. I included some sample songs--FILE.11, FILE.16, FILE.17, and +SPACE.HARRIER. Enjoy! + + SOLITAIRE: + --------- + +Klondike. I like the interface on this game. + + CAT.DOCTOR: + ---------- + +From Prosel8 (which is now public domain), this utility is very handy for +sorting directories (among other things). Useful for arranging GSOS7, +and BYE.SYSTEM mentioned above. + + BGSOUND: + ------- + +This CDA lets you play Soundsmith songs in the background while other +applications are running. Very handy for playing Solitaire with some music. + + DOCVu.CDA: + --------- + +This CDA shows the current DOC contents in real-time. It has neat visual +effects while playing Soundsmith songs. + + Zippy.gs + -------- + +Very useful ProDOS 8 program by Andy McFadden for setting ZipGS parameters. +In KEGS, you'll want to use this to change the Zip speed to less than +100% to make the "Unlimited" speed become limited to 7.5MHz, which is +useful for some games. + + +KEGS: What works: +----------------- + +Basically, just about every Apple II program works. + +KEGS is EXTREMELY compatible. But, I haven't tested everything. Let +me know if you find a program which is not working correctly. + +Some old Apple II 5.25" games require the old C600 ROM image, and don't work +with the default Apple IIgs ROM. This is not KEGS's fault--these games +don't run on a real Apple IIgs either. KEGS has built-in the old Apple II +Disk PROM which you can enable by using the IIgs control panel to set +Slot 6 to "Your Card". This allows many more Apple II games to run, and +is the recommended setting. + +The NinjaForce Megademo mostly works, but sometimes hangs in the BBS Demo. +Just skip that demo if it happens. + +The California Demo hangs at startup unless you use the IIgs control panel +to boot from slot 5, and then do a ctrl-Open_Apple-Reset to boot--doing +the above lets it work fine. This seems to be a bug in the demo. + + +KEGS bugs: +--------- + +KEGS's serial port emulation is very limited now, and only for +adventurous souls. + +On a ROM03, KEGS makes a patch to the ROM image (inside emulation, not +to the Unix file) to fix a bug in the ROM code. Both ROM01 and ROM03 +are patched to enable use of more than 8MB of memory. I then patch the ROM +self-tests to make the ROM checksum pass. But other programs, like +the Apple IIgs Diagnostic Disk, will detect a ROM checksum mismatch. +Don't worry about it. + +Sound breaks up if KEGS is unable to keep up--it should only be happening +if you are trying to force KEGS to run at 2.8MHz, but cannot due to +sound and video overhead. + + +Sound emulation: +--------------- + +KEGS supports very accurate classic Apple II sound (clicking of the +speaker using $C030) and fairly accurate Ensoniq sound. + +When KEGS determines that no sound has been produced for more than +5 seconds, it turns off the sound calculation routines for a small +speedup. It describes that it has done this by saying "Pausing sound" +in the debug window. However, when sound restarts, it sometimes +"breaks-up" a little. I will work on fixes for this. + +If your display is not using shared memory, audio defaults to off unless +you override it with "-audio 1". + +SCC emulation: +------------- + +KEGS emulates the two serial ports on a IIgs as being two Unix sockets. +Port 1 (printer port) is at socket address 6501, and port 2 (modem) +is at socket address 6502. + +In KEGS, from APPLESOFT, if you PR#1, all output will then be sent to +socket port 6501. You can see it by connecting to the port using +any method you like, but a simple, easy way is to use telnet. In +another Unix window, do: "telnet localhost 6501" and then you +will see all the output going to the "printer". + +Under APPLESOFT, you can PR#1 and IN#1. This gets input from the +socket also. You can type in the telnet window, it will be sent on +to the emulated IIgs. Telnet on Unix defaults to "line mode" which +buffers keys you type until you hit return. This can be a bit distracting, +and can be disabled by hitting Ctrl-] and then "mode char". This +causes a few {{ chars to show up in KEGS--just ignore this for now. +You may want to go to the F4 Config Panel and set "mask off high bit" +for serial port accesses to make PR#2 work a little nicer. + +That's about it. Proterm and Appleworks GS can talk to the modem port +fine, but it's limited in its usefulness. I have printed from +Printshop, but it's a bit pointless since it's sending out Imagewriter +printer codes which doesn't look like anything. You can "print" from +BASIC by using something like PR#1 in KEGS and +"telnet localhost 6501 | tee file.out" in another window. + +Feel free to let me know what doesn't work, but a lot is known not +to work. GNO's tty interface may work, but I'm having problems +testing it. + + +KEGS status area: +---------------- + +The status area is updated once each second. It displays info I am +(or was at some time) interested in seeing. + +Line 1: (Emulation speed info) +dcycs: number of seconds since KEGS was started +sim MHz: Effective speed of KEGS instruction emulation, not counting + overhead for video or sound routines. +Eff MHz: Above, but with overhead accounted for. Eff MHz is the + speed of an equivalent true Apple IIgs. This is extremely + accurate. +sec: The number of real seconds that have passed during on of KEGS's + emulated seconds. Should be 1.00 +/- .01. Under 1 + means KEGS is running a bit fast, over 1 means KEGS is + running slow. When you force speed to 2.5MHz, if KEGS + can't keep up, it extends sec, so you can see how slow + it's really going here. +vol: Apple IIgs main audio volume control, in hex, from 0-F. +pal: Super-hires palette that is unavailable. KEGS needs one palette + for the standard Apple // graphics mode on an 8-bit display, + and it grabs the least-used palette. Defaults to 0xe. + You can try changing it with F10. If you change it to a + palette that is not least used, KEGS changes it back in + one second. Any superhires lines using the unavailable + palette will have their colors mapped into the + closest-matching "lores" colors, to minimize visual + impact. +Limit: Prints which speed setting the user has requested: 1MHz, 2.8MHz, + or Unlimited. + +Line 2: (Video and X info) +xfer: In hex, number of bytes transferred to the X screen per second. +xred_cs: Percentage of Unix processor cycles that were spent in the X + server (or other processes on the machine). +ch_in: Percentage of Unix processor cycles spent checking for X input Events. +ref_l: Percentage of Unix processor cycles spent scanning the Apple IIgs + memory for changes to the current display screen memory, + and copying those changes to internal XImage buffers. +ref_x: Percentage of Unix processor cycles spent sending those XImage buffers + to the X server. Very similar to xred_cs. + +Line 3: (Interpreter overhead) +Ints: Number of Apple IIgs interrupts over the last second. +I/O: Rate of I/O through the fake smartport interface (hard drives). + Does not count 3.5" or 5.25" disk accesses. +BRK: Number of BRKs over the last second. +COP: Number of COPs over the last second. +Eng: Number of calls to the main instruction interpreter loop in the + last second. All "interrupts" or other special behavior + causes the main interpreter loop to exit. A high call + rate here indicates a lot of overhead. 12000-15000 is normal. + 20000+ indicates some sort of problem. +act: Some instructions are handled by the main interpreter loop returning + special status "actions" to main event loop. This is the + number over the last second. Should be low. +hev: This tracks HALT_EVENTs. KEGS returns to the main loop to recalc + effective speed whenever any speed-changing I/O location is + touched. See the code, mostly in moremem.c +esi: This counts the number of superhires scan-line interrupts + taken in the last second. +edi: This counts the number of Ensoniq "special events" over the last + second. A sound that stops playing always causes a KEGS + event, even if it doesn't cause a IIgs interrupt. + +Line 4: (Ensoniq DOC info) +snd1,2,3,4: Percentage of Unix processor cycles spent handling various + sound activities. snd1 is the total sum of all sound overhead. +st: Percentage of Unix cycles spent starting new Ensoniq oscillators. +est: Percentage of Unix cycles spent looking for 0 bytes in sounds. +x.yz: This final number is the average number of oscillators playing + over the last second. Up to 4.00 is low overhead, over + 20.0 is high overhead. + +Line 5: (Ensoniq DOC info) +snd_plays: Number of calls to a routine called sound_play, which + plays Ensoniq sounds. Always called at least 60 times per sec. +doc_ev: Number of Ensoniq (DOC) events in the last second. A sound + stopping is an event, but changing a parameter of a sound + while it is playing is also an event. +st_snd: Number of sounds that were started in the last second. +snd_parms: Number of times a sound parameter was changed while it + was playing. + +Line 6: (IWM info) +For each IWM device, this line displays the current track (and side for +3.5" disks). If a disk is spinning, there will be an "*" next to the +track number. Only updated once a second, so the disk arm moving may +appear to jump by several tracks. "fast_disk_emul:1" shows that KEGS +is using less accurate, but faster, IWM emulation. Press F7 to toggle +to accurate disk emulation. + + +Documentation To-Do: +------------------- + +Describe the tracing and breakpoint debug features. +Describe the debug interface. +Describe how the code works. +Describe more of what's known to work. +Describe my changes to SPEEDTEST. + +KEGS To-Do: +---------- + +Better serial port emulation (printing, comm) +Better nibblized images. +Fix the Ensoniq bugs to make sound more accurate. + +------------------- + +If you have any problems/questions/etc., just let me know. + +Special thanks to Jeff Smoot of climbingwashington.com for letting me use +the picture of a keg in the Mac icon. + +Kent Dickey +kadickey@alumni.princeton.edu + + +X Window (Linux) interface information: +-------------------------------------------- + +Every version of Linux is different. Supporting this is very difficult +especially since I do not run Linux myself. + +If KEGS fails to start, try the following options: + +kegs -audio 0 -noshm + +There may be a bug with drawing the border on x86 Linux with Shared Memory-- +add the options "-noshm -skip 0" to fix this up (but lose some graphics +performance, sorry). Try KEGS without these options first, but use +this as a workaround if necessary. + +If you want the display to go somewhere different, make sure the shell +environment variable $DISPLAY is set, or give the command-line argument +"-display {foo}". + +KEGS also forks off a subprocess to help handle the sound if audio is +active. If KEGS crashes in a unusual way (a core dump, for instance), +you may have to manually kill the subprocess. ("ps -ef| grep kegs;kill +xxxxx"). + +User geoff@gwlink.net adds some notes for mounting disks/floppies/CDs under +Solaris: + + To use a CDROM, insert the CD and let Volume Management mount it. + Edit kegs_conf and use the filesystem that shows up in the "df -k" + listing. The volume name of the CDROM must be included. For example, + a CDROM in an IDE drive would look like this: + + /vol/dev/dsk/c1t0d0/ciscocd + + A CDROM in a SCSI drive would look like this: + + /vol/dev/dsk/c0t6d0/j1170_10804 + +To provide low-level ADB emulation, KEGS turns off Unix key repeat when the +focus is in the KEGS window. It should be turned back on every time +the pointer leaves the KEGS window, but sometimes it doesn't. Re-running +KEGS (and then quitting it quickly) should turn key-repeat back on, +or you can type 'xset r' in another terminal window. + +Sometimes the converse is true--key repeat is "on" when the cursor is +in the KEGS window. Moving the cursor out of the window and then +back in should solve it. This is sometimes noticeable when running +Wolfenstein 3D GS. I haven't spent much time debugging the problem. +I think it may be the X Server. + +KEGS uses a private color-map for its X-window in 8-bit mode. This +may cause colormap "flash" when your cursor enters the window. + +KEGS details/troubleshooting +---------------------------- + +KEGS will work on all platforms with a 15/16-bit, 24-bit, or 32-bit +color display. KEGS also supports an 8-bit display on X windows only. +On all platforms, it autodetects the color depth--no color switching +is necessary as long as you're at a supported depth. + + +Disk Image Details + +Images loaded into slot 6 (drive 1 or 2) are assumed to be 140K +5.25" disks, which is usually have the extension ".dsk". Images +loaded into slot 5 (drive 1 or 2) are assumed to be 800K disk images +and can be in any supported imahe format (including partitions, if +you have 800K partitions). Images loaded into slot 7 (drives 1 +through 32) can be in any format and can be any size up to 4GB. + +KEGS boots s7d1 by default. You can change this using the emulated IIgs +control panel, just like a real Apple IIgs. KEGS emulates a IIgs with +two 5.25" drives in slot 6, two 3.5" drives in slot 5, and up to 32 +"hard drives" in slot 7. However, the current Configuration Panel only +lets you set through s7d11. + +Config.kegs file +---------------- + +KEGS saves your preferences and disk image names in the file config.kegs. +KEGS searches for this file in the directory KEGS was started in, in +your home directory, or in the Resources directory (on a Mac) of the app. +It needs to find one someplace, so putting it in your home directory is +usually the easiest. + +The config.kegs file is a simple text file. You need to quit KEGS before +editing the file. The BRAM data is also kept in this file, with separate +BRAM contents for ROM 01 and ROM 03 (so if you switch ROM versions, you +don't lose all your BRAM preferences). + +If you're trying to use a real host device (CD-ROM, or hard drive, or +floppy), you should make the permissions on the /dev/disk* files something +like (meaning, everyone should have read permission): + +brw-r--r-- 1 root operator 14, 0 Jun 10 00:01 /dev/disk2 + +You can do this on a Mac with: + +sudo chmod 644 /dev/disk2 + +Running KEGS as root is NOT recommended. + +The s6d* and s5d* drives support disk swapping and disk ejecting, but +the s7d* drives do not. + diff --git a/README.linux.partitions b/README.linux.partitions new file mode 100644 index 0000000..abfa8ed --- /dev/null +++ b/README.linux.partitions @@ -0,0 +1,252 @@ +[ This info provided by Mike Thomas ] +[ Updated 10/30/2003 by Kent: This file mentions editing "kegs.conf" to ] +[ mount images--this is now replaced by the built-in Configuration Panel. ] + +Setup and configuration for x86 Linux: +-------------------------------------- + +KEGS is very easy to setup on your Linux box, but not foolproof. First +you will need to decide where it will live. When doing this you will +have to take into consideration any users of your machine. It really +doesn't matter where it goes but it should have it's own directory and +any supplied sub-directories should be there. You may decide to use the +/usr/local path where most systems recommend you install applications. +Again, this is entirely up to you. On my system I have a separate +partition for KEGS and all the miscellaneous files I've accumulated for +it. This makes it easy for me to reinstall the system should the need +arise. Since I fool around with a large variety of software and OS's +this happens more often than it would for normal users. + +Once you have put the files into the proper place you will need to +compile it. You should not need to be 'root' to do this part. The file +README.compile explains the steps required for this. Basically all you +should need to do is set the vars link to point to the file +vars_x86linux. You will want to check the file and make sure it is +accurate for your system. On my Redhat 6.0 system the default compile +setup works fine. I use the pentium GCC compiler instead of the +supplied EGCS since it seems to build better binaries. I do not +recommend using optimization levels higher than 2. Once you have +successfully built the binaries you will need to copy them to the KEGS +directory. At a minimum copy the file kegs and to_pro. + +Ok, now that you have the binaries you're almost ready. You will need a +copy of the IIgs rom placed in the KEGS directory. It should be named +ROM. You will also need some disk images. This is the hardest part. +You will need to create an HD image to work with. Kent mentions an easy +way in his readme. From the shell type this: + +echo "testfile" > testfile +to_pro -16384 testfile + +If you're using bash try this: + +echo "testfile" > testfile +./to_pro -16384 testfile + +This should create a 16 megabyte HD image. This image will NOT be properly +formatted to boot a system. The block zero is not properly setup. There is no +easy way to fix this with the current KEGS/Linux system. There seems to be a +problem formating HD files for Prodos using KEGS. The system will easily erase +them but this doesn't help you. One solution is to make the primary boot drive +use a disk partition. This is more involved and will be explained later. +Another solution is to have access to the utility Block.Warden or some other +P8 block utility. What you need to do is copy the boot blocks (blocks 0 and 1) +from any bootable disk to the HD image. With that done you can now install +GS/OS. + +Make sure you set the proper file permissions on files needed by KEGS. You +will not be able to properly use it while logged on as root. KEGS uses the +file permissions to test if it should write the image to disk or the memory +image. As root, KEGS will never write the image since it thinks root +always has execute privilege. The main files which you will need read/write +access to are bram.data.1 and disk_conf. I suggest you have read access to all +the other files in the directory. + +Once you've got all the proper permissions set, log onto the system with your +normal account. Start up X and a shell and cd to the KEGS directory. Assuming +you have the disk images for GS/OS edit your disk_conf file so it looks +similar to this: + +# boot from install disk +s7d1 = /usr/local/fst/gsos1 + +# our HD image +# you should rename POOF1 file created with to_pro +# I use *.hdv to be compatible with other utilities +s7d2 = /usr/local/fst/boot.hdv + +# other GSOS images +s7d3 = /usr/local/fst/gsos2 +... + +If you include all the GSOS images this way you will have a simple setup. +Execute KEGS. For now go with the simplest command line possible. Since the +newer versions support auto detect on video resolutions this should be the +command kegs by itself. Hopefully you will boot into the emulator. If so, +install GSOS and you're ready to go. + + +Sound +----- + +Kent says sound doesn't work under Linux. This is partially true and much +depends on the sound system you have installed. I have been successful with +sound on both Soundblaster and Soundpro systems. For long compositions the +sound may break up but it is functional for games and system sounds. + + +System Video Setup +------------------ + +This is rather personal and based upon system hardware so I'll just give you my +thoughts and setup info on this. My normal X system is configured +@ 1152x864 15bpp due to constraints in the X server for my video system. I +have custom configured it to boot into this mode and then I change to 800x600 +by using the CTRL+ALT+(keypad)PLUS sequence when I use KEGS. This makes the +system much easier to read. + + +KEGS and disk partitions +------------------------ + +Kent mentions using partitions in his readme file but doesn't go into much +details. I suspect this is mostly for accessing CD-roms. But it also works +well for HFS and Prodos formatted partitions also. Linux can also handle HFS +partitions but not Prodos. To accomplish this you will need some free space on +your hard disk to create the partitions. You should not attempt this unless you +know what you are doing. You have been warned! + +This task is not easy, nor is it supported by Kent. This was done and tested +on my own system so I know it works. You will need the HFS support utilities +for Linux. These are available on several Linux software sites. The primary +need for these utilities is to change an ext2fs partition to an HFS partition. +You can also use them to format the HFS volumes and copy files to and from +the partition. Newer versions of the Linux kernel support HFS file systems but +you will still need the utilities to create the original volume. + +You must decide how you want to divide this partition. You can use it all for +HFS or you can create Prodos volumes and HFS volumes. There are pros and cons +for using Prodos partitions instead of files. The pros, it is a little faster +than using an HD file. It is a real Prodos partition, formatted by KEGS. The +cons, It must be backed up by using software on the emulator. You can't just +copy the HD file to another drive. + +You must weigh these pros and cons and decide for yourself. Of course you +are not limited to using partitions. I have a mix of partitions and files +which works quite well. I like the P8 partitions for holding my boot system +and applications. I back them up with GSHK to an HFS volume which I can then +transfer to another drive if I need even more security. + +If you decide to use the whole partition for HFS then all you need to do is +run the HFS utilities and setup the HFS volume. Read the documentation which +comes with the utility package and follow it faithfully. + +If you want to use P8 and HFS partitions you have some more work to do. If +you have never worked with low level partitions or are worried about destroying +your HD then you should probably forget this. For this to work you will have +to change the partition table on your HD. This can and most likely will ruin +any data you already have on there. I can not state this enough. Back up any +important data on the hard drive! It is possible to change the partitions in +Linux and not destroy the system. I have done this on mine but I also used +the last defined partition to make the changes and designed the system for +change should it be necessary. + +For those of you who know how to handle this, take the partition you have +decided to use for KEGS and divide it into at least one 32 meg partition. +More is better but you will have to use the emulator to back up any drives +setup this way since Linux can't access a Prodos partition (yet). I have setup +4 32 meg P8 partitions and several smaller HFS partitions of about 96 megs. +The reason I use smaller HFS partitions is because HFS isn't real efficient +with larger drives, but that's another story. The reason for the separate +HFS partitions is so Linux can mount the HFS volumes like any other file system. +I find this works quite easily for accessing files instead of using the HFS +utilities. Just my opinion though. For P8 utilities you will still need to +use the HFS utility and configure the drive as an HFS volume. This lets KEGS +read the partition when it loads the partition the first time. KEGS doesn't +like the Linux file system. + +Ok, everybody got their partitions defined? You want to use the HFS tools +and setup all the partitions (P8 and HFS) as HFS volumes. Next you will have +to setup the HFS partitions. No, I'm not repeating myself. This is not the same +thing as the low level partitions. HFS volumes have their own partition table. +For our purposes the table will only hold one partition on each whole volume. +The utility will give you the block count when you setup the partitions, +write it down so you don't forget. After you have the volume partition setup +you can format the drive. Yeah I know you made a Prodos partition but it +doesn't hurt anything and KEGS will be able to read the partition when it +boots up. + +Well, I think I covered everything needed to set them up. Now you will need to +edit the /etc/fstab file. Make sure there are no references to the original +partition. If you want to access the HFS volumes you will need to add them to +this file. You will also need to make sure that your Linux can understand the +HFS format. Most newer kernels will as long as you've compiled it into the +kernel or set it up as a module. KEGS doesn't need these entries to access +the volumes, they are just here for your convenience. In fact, if you don't +need Linux access I suggest you either leave them out or set them up as +NOAUTO and mount them only when needed. Unmount them when finished to avoid +any potential problems also. Do not give Linux access to any P8 partitions. +For one thing it can't recognize them and most likely will give you problems +when you boot the system. For safety's sake the only partition I have listed +in my /etc/fstab is a volume called transfer. You must set the filetype to HFS +so Linux doesn't complain about the partitions if you mount them. + +Ok, all partitions are defined, the /etc/fstab is setup correct, now you need +to change the permissions on the device files associated with the partitions. +This allows you to access the files as a normal user. (Thanks Kent, guess I +got too involved and forgot it should be treated like the CD). You will need +to reboot to ensure the system sees the new partitions and has the correct +/dev/hd?# device files. If you setup the partitions with fdisk you should know +the correct hd info to select the files. For the sake of example let's assume +the device is HDB and the partitions numbers are 1,2,3. From the shell, + +cd /dev +chmod 666 /dev/hdb1 +chmod 666 /dev/hdb2 +chmod 666 /dev/hdb3 + +After you start KEGS you can format the Prodos partitions. If you use the +method mentioned earlier for installing GS/OS you will want to quit the +installer and run the advanced disk utilities on the utilities disk, then +quit back to the installer program or reboot. + +Now I know this all sounds like a lot of trouble but (IMHO) it's worth it. For +one thing, KEGS will format a Prodos partition without problems (unlike an HD +file image) which makes a great boot system. And with GS/OS 6.01 you can access +large HFS volumes for storage and GS applications. You can also download from +the net to the HFS volume (if it's mounted) and avoid the trouble of copying +files to an image with to_pro. Not to mention the fact that the newest GNO +works with HFS drives. + +One more note, if you use HFS you will need to patch the HFS fst. There is a +one byte bug which mis-calculates HFS block sizes and WILL trash your HFS +drive. The patch is at several places on the net or ask someone in one of +the comp.sys.apple2 news groups. + +Miscellanea +----------- + +To ease access to the KEGS binary, make an executable script which contains +any command line parms you need. Then put this script somewhere in the path +so you can execute it from any shell. Depending on the desktop you use you +may want to setup links for editing the disk_conf file also. With GNO/ME you +can launch KEGS without the shell but I don't recommend this since you won't +know what happened when it dies. With KDE you can set up the launcher to use +a shell, this is much better but until you have your setup stable you will +want to use a regular terminal so you can keep track of what's going on. Like +GNO/ME, the KDE shell will close as soon as KEGS quits with an error. + + +Thanks +------ + +I hope this info helps you enjoy KEGS. Many thanks to Kent for creating this +fine emulator and for putting up with me bugging him with 'bug' reports. Many +of these weren't actually bugs but were my own fault due to lack of knowledge +about *nix systems. But Kent was prompt in fixing the ones which truly were +bugs. Thanks to him I can now play my favorite game, Questron 2 (gs version) +which requires a player disk in slot 5. I know no other emulator which can +actually play this game. + +Mike Thomas + diff --git a/README.mac b/README.mac new file mode 100644 index 0000000..92c5c0a --- /dev/null +++ b/README.mac @@ -0,0 +1,41 @@ + +MAC OS X port of KEGS (KEGSMAC): http://kegs.sourceforge.net +------------------------------------------------------------- + +There is a different port of KEGS to Mac OS X called KEGS-OSX. +You can get it from http://casags.net/. + +This port is not leveraged from KEGS-OSX (which is based on SDL). + +This is a Mac OS X Carbon port. It will not work on Mac OS 9. + +Everything pretty much works, but 8-bit color doesn't work. Make sure your +Mac is set to Thousands or Millions of colors. + +Usage: +----- + +Like most other KEGS versions, KEGSMAC is usually run from a Terminal +window. Just type "./KEGSMAC.app/Contents/MacOS/KEGSMAC" in the directory +you installed/compiled it in. You need to have a ROM file (named +ROM, ROM.01, or ROM.03) and a config.kegs in the same directory or in your +home directory (read the README--these files are searched for in various +places). + +KEGSMAC can also be run from the Finder, but if you do this, there +will be no debug window at all. This is not well tested, yet. + +To quit, either click the window close box, or select Quit from the menu. +You can also middle-click (if you have a 3-button mouse) or +Shift-F6 to get the debugger in the terminal window, and then type "q". + +Compile directions +------------------ + +In order to compile, + +1) cd into the src/ directory +2) copy vars_mac to vars +3) run make + +You can contact me at kadickey@alumni.princeton.edu diff --git a/README.win32 b/README.win32 new file mode 100644 index 0000000..182958a --- /dev/null +++ b/README.win32 @@ -0,0 +1,51 @@ + +WIN32 port of KEGS (KEGSWIN) +---------------------------- + +There is a different port of KEGS by akilgard called KEGS32. +You can get it from http://www.geocities.com/akilgard/kegs32. +This port is leveraged from KEGS32, but mostly a rewrite (perhaps +for the worse). The joystick code was taken without too many +modifications. + +This port is alpha quality. Seriously. Don't expect much. + +This is a bare-bones Win32 port. It was compiled with Mingw2.0, +which you can download at: http://www.mingw.org/. I also had +previously installed cygwin at http://www.cygwin.com/. Installing +these two beasts is a bit of a pain, so I'll eventually write up +directions (I hope). + +Sound works, the mouse works, and a joystick might work (ported +from KEGS32). The user-interface is just like every other KEGS +version (i.e., bad), so you can just read the standard README file. + +Only tested on a 32-bit graphics display, although I think 16-bit and +24-bit will work. 8-bit definitely does not work. There are many +other bugs I just haven't had time to list yet. + +Usage: +----- + +Like most other KEGS versions, KEGSWIN must be run from a terminal +window (command.com is fine). Just type "KEGSWIN" in the directory +you installed/compiled it in. You need to have a ROM file (named +ROM, ROM.01, or ROM.03) and a kegs_conf in the same directory (or +read the README--these files are searched for in various places). + +To quit, either click the close box, or force quit the application. +You can also middle-click (if you have a 3-button mouse) or +Shift-F6 to get the debugger in the terminal window, and then type "q". + +Compile directions +------------------ + +In order to compile, + +1) cd into the src/ directory +2) rm vars +3) ln -s vars_win32 vars +3) ./make_win + + +You can contact me at kadickey@alumni.princeton.edu diff --git a/config.kegs b/config.kegs new file mode 100644 index 0000000..bef86d2 --- /dev/null +++ b/config.kegs @@ -0,0 +1,11 @@ +# KEGS configuration file version 0.80 + +s5d1 = XMAS_DEMO +s5d2 = + +s6d1 = #dos33.dsk +s6d2 = + +s7d1 = NUCLEUS03 + + diff --git a/kegswin.exe b/kegswin.exe new file mode 100755 index 0000000..b6c6563 Binary files /dev/null and b/kegswin.exe differ diff --git a/src/INTERNALS.iwm b/src/INTERNALS.iwm new file mode 100644 index 0000000..3be8c16 --- /dev/null +++ b/src/INTERNALS.iwm @@ -0,0 +1,239 @@ + +KEGS's Apple //gs IWM emulation routines. + +The IWM code does 5.25" and 3.5" reads & writes, and updates the Unix disk +image on writes. It is also nearly cycle-accurate--Let me know if you +have a program which can detect it's not a real Apple II. There are +a few 5.25" features missing (No 1/4 or 1/2 tracks, no support for Unix nibble +images, limited disk switching), but what's there is pretty accurate. +The low-level code support 1/4 and 1/2 tracks--it's the arm movement +and image-handling routines which don't. And lack of Unix nibble images +are also due to lack of higher-level routines to make those features work. + +How my disk emulation works: The routines have a nibblized image of each +track of each drive (two 5.25" and two 3.5" drives are supported) in memory. +The nibble images are declared as arrays, but it could be made to use +more dynamic memory allocation. + +Each track's data format is a series of two-byte pairs. The first byte +of the pair is the number of bits in this disk byte, and the second byte +is the value. So a size of 8 is normal. A size of 10 means that there +are 2 sync bits written before this byte on the disk. So for 5.25" disk +accesses, 40 cycles need to pass in the simulator before providing a +valid nibble. Partial nibbles are correctly formed if a read happens +too early (this actually makes things slower, but is required if you +want to make nibble copiers work). Similarly, writing to the disk +watches timing carefully to write out the correct number of bits per +disk byte. These routines will definitely test out your emulator's cycle +counting ability. + +If a long delay occurs between a read (or a write) the routines skips +the correct number of bits to return the correctly formed disk byte. +After a long delay, for efficiency, I always return a full disk byte, +instead of a partial one, even if the timing would put it in the middle +of a disk byte. + +The arm stepping is really lame. I will clean it up soon. + +Smartport support is sufficient to claim that there are no smartport +devices. This is necessary since the ROM tries to see if there are +smartport devices at power-on. + +I tested my 5.25" drive routines on EDD, which could correctly measure +drive speed and other disk factors. I also nibble-copied some disks, +which also worked fine. I tested the 3.5" routines using Copy II+, +which successfully nibble-copied several disks. + + +Code description: + +Most code is in iwm.c, with some defines in iwm.h, and some stuff in +iwm_35_525.h. + +Code only supports DOS3.3 ordered 5.25" images now, and ProDOS-ordered 3.5" +images. Well, the code supports ProDOS-order 5.25" also, but has no +mechanism to tell it an image is prodos-order yet. :-) + +Iwm state is encoded in the Iwm structure. + + drive525[2]: Disk structure for each 5.25" disk + drive35[2]: Disk structure for each 3.5" disk + smarport[32]: Disk structure for each "smartport" device emulated + via slot 7 (this code not included) + motor_on: True if IWM motor_on signal (c0e9) is asserted. Some + drive is on. + motor_off: True if motor has been turned off in software, but the + 1 second timeout has not expired yet. + motor_on35: True if 3.5" motor is on (controlled differently than + 5.25" c0e9). + motor_off_vbl_count: VBL count to turn motor off. + head35, step_direction35: 3.5" controls, useless. + iwm_phase[4]: Has '1' for each 5.25" phase that is on. + iwm_mode: IWM mode register. + drive_select: 0 = drive 1, 1 = drive 2. + q6, q7: IWM q6, q7 registers. + enable2: Smartport /ENABLE2 asserted. + reset: Smartport /RESET asserted. + previous_write_val: Partial write value. + previous_write_bits: How many bits are valid in previous_write_val. + +Each disk (3.5" and 5.25") is encoded in the Disk struct: + fd: Unix file descriptor. If < 0, no disk. + name_ptr: Unix file name for this disk. + image_start: offset from beginning of file for this partition. + image_size: size of this partition. + smartport: 1 if this is a smartport image, 0 if it is 5.25" or 3.5" + disk_525: 1 if this is a 5.25" image, 0 if it is 3.5" + drive: 0 = drive 1, 1 = drive 2. + cur_qtr_track: Current qtr track. So track 1 == qtr_track 4. + For 3.5", cur_qtr_track encodes the side also, so track 3 + side 1 would be qtr_track 7. + prodos_order: True if Unix image is ProDOS order. + vol_num: DOS3.3 volume number to use. Always 254. + write_prot: True if disk is write protected. + write_through_to_unix: True if writes should be passed through to + the unix image. If this is false, you can write + to the image in memory, but it won't get reflected + into the Unix file. If you create a non-DOS3.3 + or ProDOS format image, it automatically sets this + false. + disk_dirty: Some track has dirty data that need to be flushed. + just_ejected: Ejection flag. + dcycs_last_read: Cycle count of last disk data register access. + last_phase: Phase number last accessed. + nib_pos: Nibble offset ptr--points to a byte. + num_tracks: Number of tracks: 140 for 5.25" and 160 for 3.5" + track[MAX_TRACKS]: nibble image of all possible tracks. + +Each track is represented by the Track structure: + track_dirty: Contains data that needs to be written back to + the Unix image file. + overflow_size: Count of overflow bits, used in writing. + track_len: Number of nibbles on this track. + dsk: Handy pointer to parent Disk structure. + nib_area[]: ptr to memory containing pairs of [size,data], + encoding disk data bytes. + pad1: If the structure is 32 bytes long, some array + indexing is done better by my compiler. + + +Externally callable routines: +iwm_init(): Init various data structures at simulation start. +iwm_reset(): Called at Apple //gs reset time. +iwm_vbl_update(): Called every VBL (60 Hz) period. Used to turn motor + off, and flush out dirty data. + g_vbl_count is the count of VBL ticks (so it counts + at 60 times a second). +iwm_read_c0ec(double dcycs): Optimized routine to handle reading $C0EC + faster. Exactly the same as read_iwm(0xc, dcycs); +read_iwm(loc, dcycs): + Read from 0xc0e0 + loc. Loc is between 0x0 and 0xf. + Dcycs is an artifact from my simulator. Dcycs is a + double holding the number of Apple //gs cycles since the + emulator started. Dcycs always counts at 1.024MHz. If + you are running at 2.5MHz, it increments by 0.4 every + "cycle". This is a very convenient timing strategy. It + also allows emulating the delay caused by synchronizing + the fast part of a real Apple //gs with slow memory, + which means my emulator knows that reading softswitches + takes longer than reading fast memory. +write_iwm(int loc, int val, double dcycs): + Write to 0xc0e0 + loc. Just like read_iwm, but write "val" into + loc. + + +Tricky routines: + +IWM_READ_ROUT(): called by read_iwm() if q6,q7 = 0,0. + This is actually in the file iwm_35_525.h. This is so I + write the basic code once for 5.25" and 3.5" disk reads, + but then include the file with some macros set to create + the correct function optimized for 5.25" or 3.5" + accesses. The function for 5.25" is called + iwm_read_data_525, and iwm_read_data_35 for 3.5". + Returns next disk byte. + Takes three arguments: ptr to the Disk structure for + the active drive, fast_disk_emul, and dcycs. dcycs is + so that it can see how many cycles have passed since + the last read (stored in dsk->dcycs_last_read). + 16.0 dcycs need to pass for an 8 bit nibble for 3.5" + accesses, and 32.0 dcycs for an 8 bit nibble for 5.25". + Fast_disk_emul == 1 says don't mess around with accuracy, + and always return the next fully-formed nibble. + There is a lot of complexity in this routine. All IWM + routines must skip over nibbles (stored as byte pairs in + dsk->nib_area[]) which have a size of 0 (special padding + trick, described later). It then determines how much + time has passed, and so how many bits are valid. + If too many bits have gone by (11 cycs is almost 3 5.25" + bit times, which is about the nibble valid time in + the Apple //gs IWM hardware latch), it tries to skip + to the correct position. + Handles IWM latch mode for 3.5" or 5.25" accesses. If a + partial read is indicated, it ensures that the high bit + is clear by shifting the nibble to the right + appropriately. Again, nib_area[] is an array of bytes, + which are treated as pairs. Byte 0 = size, byte 1 = + disk nibble. + +IWM_WRITE_ROUT(): called by write_iwm() if q6,q7 = 1,1. + Similar to above. Handles async and sync mode writes. + Handles partial writes. Handles the ROM writing + 0xff, 0x3f, 0xcf, 0xf3, 0xfc to be four 10-bit nibbles. + Routine disk_nib_out(dsk, val, bits_read) does the + actual work of merging the bits into the track image. + +disk_nib_out(): called by IWM_WRITE_ROUTE() and iwm_nibblize_track_*(). + Writes byte into nib_area[]. If size > 10, makes it 10. + If high order bit not set, it sets it (makes certain routines + in EDD happy). + +overflow_size: + Writing to the disk creates some problems. I need to + maintain 2 things at all times on the track: + 1) Constant number of bits for the entire track. + 2) know where each synchronized byte starts on + the track. + If the track was just stored as raw bits, then correctly + simulating a delay of 300*4 cycles is tough, since it has to + be done by reading through all 300 bits on the track, + so that we keep in sync with where bytes really start. + But if you just store the bytes themselves, then sync + bytes look like every other byte. And if you now add + the size field, you have a situation where a track could + gain or lose bits when rewritten. Here's the case: + Assume the track contains: 10,ff 10,ff 10,ff 10,ff. + (That is 4 self-sync disk bytes of 10 bits each). + If we rewrite that area of the track with 'D5 AA 96 FF', + where each byte is 8 bits, we would have: + 8,D5 8,AA, 8,96, 8,FF. + Looks OK, but we just lost 8 bits! The original 4 nibbles + were using 40 bits of space on the disk. Our new 4 nibbles + are using 32 bits. 8 bits are lost. + Solution: log these missing bits via overflow_size. + When writing, if overflow_size gets > 8, force out a 0,0 + nibble. So sync bytes get written as: + 10,FF 10,FF 10,FF 10,FF 0,0 10,FF 10,FF 10,FF 10,FF, 0,0. + So when they get re-written with 8,xx, we don't lose any + bytes on the disk. + + Unfortunately, it doesn't quite work that easily, and bits + can still be lost when sync fields are partially overwritten. + This happens when all the 0,0's end up in a place on the + track where few overwrites occur, but other sync bytes + are being turned into 8,xx. So overflow_size goes negative, + saying we've got too much on the track. + The code prints an error when it gains more than 64 bits. + If someone can come up with a better scheme, I'd love to + hear it. A partial solution would be to have a routine + re-space the track to spread the needed 0,0's around + a little better when overflow_size gets too negative. + + +In iwm_nibblize_track_35(), the comments with hex numbers correspond +to the ROM 01 addresses which I disassembled to determine the checksum +algorithm. The code is not well written--it's basically hand-translated +65816 assembly code. I'll clean it up someday. + +Much of the code is not well-optimized. I'll get to that someday, but +the speed has been adequate for me so far. diff --git a/src/INTERNALS.overview b/src/INTERNALS.overview new file mode 100644 index 0000000..ef92495 --- /dev/null +++ b/src/INTERNALS.overview @@ -0,0 +1,96 @@ + +KEGS Internals +-------------- + +The INTERNALS* files describe the internal structure of KEGS and how +it works. It is meant to be useful to those who would attempt to +port KEGS to non-Unix platforms, or just want to know how KEGS works. + +Documentation files: +-------------------- + +INTERNALS.overview: Provides overview of KEGS's file structure + + +KEGS SOURCE FILES: +----------------- + +adb.c: ADB emulation routines. This includes keyboard, mouse, and + joystick. +adb.h: Defines for ADB routines. +clock.c: Clock, BRAM, and some timing routines. +compile_time.c: Trick file to put the time you compiled in g_compile_time[]. +defc.h: Global defines included by all .c files. Useful trick + to avoid complex multi-level include problems. +defs.h: Global defines included by all .s files (assembly language). +defcomm.h: Global defines included by all files (must be assembly and + C safe, such as #defines). +defs_instr.h: C and assembly definitions for various addressing modes + and for some repeated instructions (like LDA, STA, etc). +dis.c: Disassembler and debugger interface. The debugger interface + is similar to the Apple // monitor, but has many + more commands. +disas.h: Tables for disassembling 65816 instructions. Not very + efficient, but it works. +engine_c.c: C main instruction dispatch loop. +engine_s.s: Assembly main instruction dispatch loop. +instable.h: Instruction table. It is C and assembly-safe through + the make_inst script. make_inst turns instable.h into + 8inst_c and 16inst_c, which are both valid C code. +iwm.c: IWM routines for 5.25" and 3.5" disks. See INTERNALS.iwm +iwm.h: IWM defines +iwm_35_525.h: File for reading and writing a disk byte, which is included + in iwm.c twice, once for 5.25" and again for 3.5". + Forcing out compile-time constants this way makes it + faster. +moremem.c: Awful name--this file contains the page table change + routines (fixup_*) and io_read() and io_write() to + emulate all $C000 I/O accesses. +op_routs.h: More macros for 65816 emulation. +protos.h: Prototypes for all C functions. Auto-generated through + the "cproto" program (not included). +protos_xdriver.h: Prototypes for functions in xdriver.c. +scc.c: Serial chip emulation. +scc_driver.h: Unix-specific socket routines, stubbed out if you're not + on Linux or HP-UX. +scc.h: Defines for scc.c. +sim65816.c: main() is here along with many other housekeeping + functions, such as events, and interrupts. + The main loop of KEGS is run_prog(). +size_tab.h: Used by assembly for a jump table (make_size script + turns it into 8size_s and 16size_s) and by both C and + assembly to get the size of instructions. +smartport.c: Smartport emulation, emulates s7dx devices. +sound.c: Sound emulation. Builds sound samples, but does not + send sound to output device. +sound.h: Header file for sound.c. +sound_driver.c: Sound driver routines. Takes samples generated by sound.c + and sends them to the correct output device. Supports + HP Alib, HP /dev/audio, and Linux /dev/dsp currently. +superhires.h: "macro" routine used by video.c so that I could write + one generic superhires routine, but then include it + multiple times to get optimized 320 vs 640 mode routines. +video.c: Display routines. Builds 8 bit video buffers in a + device independent way. Functions here know nothing + about X windows. +xdriver.c: X windows driver routines. Takes buffers from video.c + and sends them on to X windows. Get keypresses from + X and sends them to adb.c. + +Porting Advice: +-------------- + +To a non-unix platform, disabling scc emulation would be a good start. +Just make sure you get the dummy stub routines in scc_driver.h. + +If you don't have gettimeofday(), clock.c will need to modified with +whatever timer facilities are available. A high-resolution clock works +best, but even a low-resolution clock will work. + +Modify sound_driver.c to get it to compile, if necessary. Always run with +"-audio 0" to turn audio off. No routines in sound_driver.c will get +called if you run with -audio 0. + +Replace xdriver.c with new routines for whatever platform you are porting to. +See INTERNALS.xdriver for more information. + diff --git a/src/INTERNALS.xdriver b/src/INTERNALS.xdriver new file mode 100644 index 0000000..bea9011 --- /dev/null +++ b/src/INTERNALS.xdriver @@ -0,0 +1,148 @@ + +xdriver.c contains the routines for interfacing to X windows. The rest +of KEGS interacts with X windows only through xdriver.c routines. + +Externally called routines are: +show_xcolor_array(): Debug routine, it does not need to do anything. +dev_video_init(): Called at startup, it should open up the + window and do other initialization. +update_physical_colormap(): Updates the X windows palette with the colors + from xcolor_a2vid_array[], which is maintained by + other xdriver routines. +update_status_line(): Call to update the internal array of chars + representing the status lines at the bottom of + the window. Does not draw the chars to the screen. +xdriver_end(): Shutdown routine +check_input_events(): Called up to 60 times a second (see video_update() in + video.c) to handle any X window events and get + keypresses. + On a mouse press, call update_mouse() with the + new x, y coordinates, and the status of the mouse + button. + If g_warp_pointer is set, constrain mouse within + the window. + On keypress, calls handle_keysym(). + handle_keysym(): Takes X keysym, and converts to the appropriate + a2code using the a2_key_to_xsym[] lookup table. + The a2codes are the Apple // ADB keycodes. + Special work is done to handle shift and control + properly since Apple only has one keycode for both + shift and control keys. Then call + adb_physical_key_update() with the a2 keycode and + is_up = 1 if keyup, 0 = if key down. + In addition, this routine handles all the Function + keys doing special actions, which should be easy to + port. +x_refresh_ximage(): Redraws the window using the a2_line_* arrays. + Described in more detail below. +update_color_array(): Interface to the color map. Sets color[col_num] + of the internal colormap array to a2_color. + a2_color is the 12 bit apple color of the form: + (red << 8) + (green << 4) + (blue). + There are 16 palettes of 16 colors each, managed as + one 256-color colormap. See discussion of + g_a2vid_palette below. +x_auto_repeat_on(): The X routines turn off key repeat when the cursor + enters the graphics window automatically, and turn + it back on when the cursor leaves. But if the + debugger gets control due to a breakpoint, keyrepeat + would be left off. So the debugger calls this + routine to make sure key repeat is back on. +redraw_status_lines(): Draw the status lines from the g_status_buf[][] array + to the graphics window. + +Externally referenced data: + +g_use_shmem: Set by main() to enable/disable MIT-SHM for X. + Also used by sound routines to auto-turn-off sound + if not using MIT-SHM. + +Bytes representing screen data: +byte *data_text[2]: Array of bytes for the lores and text pages 1 and 2. + Just 400*640 bytes. +byte *data_hires[2]: Array of bytes for the hires pages 1 and 2. +byte *data_superhires: Array of bytes for superhires screen. +byte *data_border_sides: Array of bytes representing the border sides. + Basically just A2_WINDOW_HEIGHT*EFF_BORDER_WIDTH bytes. +byte *data_border_special: Top and bottom border bytes. + (X_A2_WINDOW_HEIGHT - A2_WINDOW_HEIGHT + 2*8) * + (X_A2_WINDOW_WIDTH) bytes. + +Handles used for X windows drawing: +XImage *ximage_hires[2]: Opaque handle to XImage object for hires page 1 and + page 2. +XImage *ximage_text[2]: Text pages 1 and 2. +XImage *ximage_superhires: Superhires graphics XImage +XImage *ximage_border_special: Top and bottom border XImage. +XImage *ximage_border_sides: Left and right sides (only one copy, it is + drawn at two different locations to be both sides). + +Basic operation of xdriver: +-------------------------- + +X windows can push arrays of bytes to the screen through structures +called XImages. An XImage is a structure describing an offscreen bitmap. +For efficiency of page flipping, KEGS maintains separate bitmaps for the +two lores/text screens, the two hires screens, and the superhires screen. +It also maintains bitmaps for the border. For MIT-SHM to work, X +requires a unique XImage for each bitmap, and the bitmap must be allocated +within xdriver.c since it must be obtained through an shmat() call. +The X code also has non-MIT-SHM code which allocates the data_* buffers +just through malloc(). + +All bitmaps are 8-bits of Pseudo-color. The color arrays are managed +through the update_color_array() and update_physical_colormap() routines. +KEGS manages all 256 colors in the colormap as 16 palettes of 16 colors. +One of the palettes is reserved for the 16 lores colors, and is +indicated by the variable g_a2vid_palette. It defaults to 0xe. +Update_color_array() is called to update superhires colormap entries. +Update_color_array must not update colors corresponding to g_a2vid_palette. +Update_physical_colormap() pushes the color array managed by +update_color_array() to the screen, but first forces the lores colors into +the g_a2vid_palette palette. g_installed_full_superhires_colormap is +always false in KEGS for now. video.c calls update_color_array and changes +g_a2vid_palette. No xdriver routines gets notified when g_a2vid_palette +changes, so update_physical_colormap must handle the case where +g_a2vid_palette might have changed since it was last called. + +x_redraw_ximage(): +Routines in video.c are free to draw into the corresponding data_* +arrays to change any byte at any time. video.c manages remembering +which lines need to be redrawn and which parts of the screen are in +which video mode via the a2_line_* arrays. + +KEGS divides the video screen up into 25 groups, corresponding to each +text line. Each of these groups consists of 16 sublines. 25*8 = 400 lines. +(video.c has already doubled the vertical resolution in all video modes). +KEGS can allow any group to be from any of the five screens it manages: +The two text/lores pages, the two hires pages, and the superhires screen. +For each group, KEGS keeps track of what part of it needs to be redrawn. +g_a2_screen_buffer_changed has a bit set for each group which has changed +since the last call to x_redraw_ximage(). The rightmost bit (bit 0) +corresponds to group 0. If g_a2_screen_buffer_changed == 0, no groups +need to be redrawn. x_redraw_ximage clears out g_a2_screen_buffer_changed +after drawing the screen. + +For each group, a2_line_left_edge[] and a2_line_right_edge give the pixel +offsets of what should be redrawn. a2_line_xim[] gives the ximage handle +of what needs to be redrawn. KEGS always redraws 8 verticals of a group. +g_full_refresh_needed also has one bit set in it for each group, which +indicates overriding the a2_line_*_edge functions and redraw from 0 to +640 pixels of each group that needs to be redrawn. x_redraw_ximage() +interprets this information now using a simple algorithm: Skip over +groups which have not changed (using g_a2_screen_buffer_changed). +Save the ximage of this group, the left pixel and the right pixel. +Continue with the next group if it has changed. Widen the pixel region +and keep sucking up new groups to the same ximage. At group 25, or +when the ximage changes, call x_refresh_lines to redraw this large +rectangle from this ximage. x_refresh_lines() knows the ximage +corresponding to the border for the last group has to be handled +specially since the border group is not 640*400 pixels like the others. + +Other porting info: +a2_key_to_xsym[][3] contains the mapping function from X keysyms to +a2 keycodes. The first element is the a2 keycode, the second element +is the unshifted X keysym, and the third element is the shifted keysym. +A port must make the conversion to a2 keycodes, and provide up and +down events. + diff --git a/src/Info.plist b/src/Info.plist new file mode 100644 index 0000000..15a616a --- /dev/null +++ b/src/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + KEGSMAC + CFBundleIconFile + kegsicon.icns + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 0.1 + CSResourcesFileMapped + + + diff --git a/src/InfoPlist.strings b/src/InfoPlist.strings new file mode 100644 index 0000000..036ca1e Binary files /dev/null and b/src/InfoPlist.strings differ diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..158f58b --- /dev/null +++ b/src/Makefile @@ -0,0 +1,123 @@ +# $Id: release_makefile_base,v 1.15 2003/11/21 20:00:42 kentd Exp $ + +OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \ + joystick_driver.o moremem.o paddles.o sim65816.o smartport.o \ + sound.o sound_driver.o video.o scc_socket_driver.o scc_windriver.o \ + scc_macdriver.o + +include vars + +.SUFFIXES: .dep .proto + +AS = $(CC) + +XLIBS = -L/usr/X11R6/lib +PERL = perl + +all: $(TARGET) + +specials: 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s + +specials_clean: + rm -f 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s + + +# Mac builds: +kegsmac: $(OBJECTS) compile_time.o + $(CC) $(CCOPTS) $(LDOPTS) -arch ppc $(OBJECTS) compile_time.o $(LDFLAGS) -o kegsmac $(EXTRA_LIBS) -prebind -framework Carbon + mkdir -p ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib + mkdir -p ../KEGSMAC.app/Contents/MacOS + mv kegsmac ../KEGSMAC.app/Contents/MacOS/KEGSMAC + echo "APPL????" > ../KEGSMAC.app/Contents/PkgInfo + cp -f Info.plist ../KEGSMAC.app/Contents/ + cp -f InfoPlist.strings ../KEGSMAC.app/Contents/Resources/English.lproj/ + cp -f info.nib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib + cp -f classes.nib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib + cp -f objects.xib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib + cp -f kegsicon.icns ../KEGSMAC.app/Contents/Resources/ + touch '../KEGSMAC.app/Icon?' + +# Linux for X builds: +xkegs: $(OBJECTS) compile_time.o + $(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(XLIBS) $(EXTRA_LIBS) -lX11 + mv xkegs .. + +# Cygwin for X builds: +kegs.exe: $(OBJECTS) compile_time.o + $(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(XLIBS) $(EXTRA_LIBS) -lXext -lX11 -lm + mv kegs.exe .. + +# Mingw32 (native windows) builds: +kegswin.exe: $(OBJECTS) compile_time.o + $(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 + mv $(NAME)$(SUFFIX) .. + + +8inst_c.h: instable.h + $(PERL) make_inst c 8 instable.h > 8inst_c.h + +16inst_c.h: instable.h + $(PERL) make_inst c 16 instable.h > 16inst_c.h + +size_c.h: size_tab.h + $(PERL) make_size c size_tab.h > size_c.h + +engine_c.o: 8inst_c.h 16inst_c.h size_c.h + +8inst_s.h: instable.h + $(PERL) make_inst s 8 instable.h > 8inst_s.h + +16inst_s.h: instable.h + $(PERL) make_inst s 16 instable.h > 16inst_s.h + +size_s.h: size_tab.h + $(PERL) make_size s size_tab.h > size_s.h + +8size_s.h: size_tab.h + $(PERL) make_size 8 size_tab.h > 8size_s.h + +16size_s.h: size_tab.h + $(PERL) make_size 16 size_tab.h > 16size_s.h + +engine_s.o: 8inst_s.h 16inst_s.h 8size_s.h 16size_s.h size_s.h + +.s.o: + $(AS) -c $(OPTS) -I. $*.s + +.c.o: + $(CC) $(CCOPTS) $(XOPTS) -c $(OPTS) -I. $*.c + +partls: partls.c + cc $(CCOPTS) $(XOPTS) $(OPTS) -o partls partls.c + +to_pro: prodos.h prodos_protos.h to_pro.c + cc $(CCOPTS) $(XOPTS) $(OPTS) -o to_pro to_pro.c + + +compile_time.o: $(OBJECTS) + + +# dependency stuff +adb.o: adb.c adb.h defc.h defcomm.h iwm.h protos.h +engine_c.o: engine_c.c defc.h defcomm.h iwm.h protos.h protos_engine_c.h size_c.h op_routs.h defs_instr.h 8inst_c.h 16inst_c.h +clock.o: clock.c defc.h defcomm.h iwm.h protos.h +compile_time.o: compile_time.c +config.o: config.c defc.h defcomm.h iwm.h protos.h config.h +dis.o: dis.c defc.h defcomm.h iwm.h protos.h disas.h +scc.o: scc.c defc.h defcomm.h iwm.h protos.h scc.h +scc_socket_driver.o: scc_socket_driver.c defc.h defcomm.h iwm.h protos.h scc.h +scc_windriver.o: scc_windriver.c defc.h defcomm.h iwm.h protos.h scc.h +scc_macdriver.o: scc_macdriver.c defc.h defcomm.h iwm.h protos.h scc.h +iwm.o: iwm.c defc.h defcomm.h iwm.h protos.h iwm_35_525.h +joystick_driver.o: joystick_driver.c defc.h defcomm.h iwm.h protos.h +moremem.o: moremem.c defc.h defcomm.h iwm.h protos.h +paddles.o: paddles.c defc.h defcomm.h iwm.h protos.h +sim65816.o: sim65816.c defc.h defcomm.h iwm.h protos.h +smartport.o: smartport.c defc.h defcomm.h iwm.h protos.h +sound.o: sound.c defc.h defcomm.h iwm.h protos.h sound.h +sound_driver.o: sound_driver.c defc.h defcomm.h iwm.h protos.h sound.h +video.o: video.c defc.h defcomm.h iwm.h protos.h superhires.h kegsfont.h +macdriver.o: macdriver.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h +macsnd_driver.o: macsnd_driver.c defc.h defcomm.h iwm.h protos.h sound.h +windriver.o: windriver.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h +win32snd_driver.o: win32snd_driver.c defc.h defcomm.h iwm.h protos.h sound.h diff --git a/src/adb.c b/src/adb.c new file mode 100644 index 0000000..0ebb103 --- /dev/null +++ b/src/adb.c @@ -0,0 +1,1760 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_adb_c[] = "@(#)$KmKId: adb.c,v 1.63 2004-03-23 18:46:25-05 kentd Exp $"; + +/* adb_mode bit 3 and bit 2 (faster repeats for arrows and space/del) not done*/ + +#include "adb.h" + +extern int Verbose; +extern word32 g_vbl_count; +extern int g_num_lines_prev_superhires640; +extern int g_num_lines_prev_superhires; +extern int g_rom_version; +extern int g_fast_disk_emul; +extern int g_limit_speed; +extern int g_swap_paddles; +extern int g_invert_paddles; +extern int g_a2vid_palette; +extern int g_config_control_panel; +extern word32 g_cfg_vbl_count; + +extern byte *g_slow_memory_ptr; +extern byte *g_memory_ptr; +extern word32 g_mem_size_total; + +enum { + ADB_IDLE = 0, + ADB_IN_CMD, + ADB_SENDING_DATA, +}; + +#define ADB_C027_MOUSE_DATA 0x80 +#define ADB_C027_MOUSE_INT 0x40 +#define ADB_C027_DATA_VALID 0x20 +#define ADB_C027_DATA_INT 0x10 +#define ADB_C027_KBD_VALID 0x08 +#define ADB_C027_KBD_INT 0x04 +#define ADB_C027_MOUSE_COORD 0x02 +#define ADB_C027_CMD_FULL 0x01 + +#define ADB_C027_NEG_MASK ( ~ ( \ + ADB_C027_MOUSE_DATA | ADB_C027_DATA_VALID | \ + ADB_C027_KBD_VALID | ADB_C027_MOUSE_COORD | \ + ADB_C027_CMD_FULL)) + + +int halt_on_all_c027 = 0; + +word32 g_adb_repeat_delay = 45; +word32 g_adb_repeat_rate = 3; +word32 g_adb_repeat_info = 0x23; +word32 g_adb_char_set = 0x0; +word32 g_adb_layout_lang = 0x0; + +word32 g_adb_interrupt_byte = 0; +int g_adb_state = ADB_IDLE; + +word32 g_adb_cmd = (word32)-1; +int g_adb_cmd_len = 0; +int g_adb_cmd_so_far = 0; +word32 g_adb_cmd_data[16]; + +#define MAX_ADB_DATA_PEND 16 + +word32 g_adb_data[MAX_ADB_DATA_PEND]; +int g_adb_data_pending = 0; + +word32 g_c027_val = 0; +word32 g_c025_val = 0; + +byte adb_memory[256]; + +word32 g_adb_mode = 0; /* mode set via set_modes, clear_modes */ + +int g_warp_pointer = 0; +int g_hide_pointer = 0; +int g_unhide_pointer = 0; + + +int g_mouse_a2_x = 0; +int g_mouse_a2_y = 0; +int g_mouse_a2_button = 0; +int g_mouse_fifo_pos = 0; + +#define ADB_MOUSE_FIFO 8 + +int g_mouse_fifo_x[ADB_MOUSE_FIFO] = { 0 }; +int g_mouse_fifo_y[ADB_MOUSE_FIFO] = { 0 }; +int g_mouse_fifo_buttons[ADB_MOUSE_FIFO] = { 0 }; + +int g_mouse_warp_x = 0; +int g_mouse_warp_y = 0; + +int g_adb_mouse_valid_data = 0; +int g_adb_mouse_coord = 0; + +int g_adb_data_int_sent = 0; +int g_adb_mouse_int_sent = 0; +int g_adb_kbd_srq_sent = 0; + + +#define MAX_KBD_BUF 8 + +int g_key_down = 0; +int g_hard_key_down = 0; +int g_a2code_down = 0; +int g_kbd_read_no_update = 0; +int g_kbd_chars_buffered = 0; +int g_kbd_buf[MAX_KBD_BUF]; +word32 g_adb_repeat_vbl = 0; + +int g_kbd_dev_addr = 2; /* ADB physical kbd addr */ +int g_mouse_dev_addr = 3; /* ADB physical mouse addr */ + +int g_kbd_ctl_addr = 2; /* ADB microcontroller's kbd addr */ +int g_mouse_ctl_addr = 3; /* ADB ucontroller's mouse addr*/ + /* above are ucontroller's VIEW of where mouse/kbd */ + /* are...if they are moved, mouse/keyboard funcs */ + /* should stop (c025, c000, c024, etc). */ + +word32 g_virtual_key_up[4]; /* bitmask of all possible 128 a2codes */ + /* indicates which keys are up=1 by bit */ + +#define SHIFT_DOWN ( (g_c025_val & 0x01) ) +#define CTRL_DOWN ( (g_c025_val & 0x02) ) +#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) +#define OPTION_DOWN ( (g_c025_val & 0x40) ) +#define CMD_DOWN ( (g_c025_val & 0x80) ) + + +#define MAX_ADB_KBD_REG3 16 + +int g_kbd_reg0_pos = 0; +int g_kbd_reg0_data[MAX_ADB_KBD_REG3]; +int g_kbd_reg3_16bit = 0x602; /* also set in adb_reset()! */ + + +int g_adb_init = 0; + +void +adb_init() +{ + int keycode; + int i; + + if(g_adb_init) { + halt_printf("g_adb_init = %d!\n", g_adb_init); + } + g_adb_init = 1; + + for(i = 0; i < 128; i++) { + keycode = a2_key_to_ascii[i][0]; + if(keycode != i) { + printf("ADB keycode lost/skipped: i=%x: keycode=%x\n", + i, keycode); + my_exit(1); + } + } + + g_c025_val = 0; + + for(i = 0; i < 4; i++) { + g_virtual_key_up[i] = -1; + } + + adb_reset(); +} + + +void +adb_reset() +{ + + g_c027_val = 0; + + g_key_down = 0; + + g_kbd_dev_addr = 2; + g_mouse_dev_addr = 3; + + g_kbd_ctl_addr = 2; + g_mouse_ctl_addr = 3; + + g_adb_data_int_sent = 0; + g_adb_mouse_int_sent = 0; + g_adb_kbd_srq_sent = 0; + + g_adb_data_pending = 0; + g_adb_interrupt_byte = 0; + g_adb_state = ADB_IDLE; + g_adb_mouse_coord = 0; + g_adb_mouse_valid_data = 0; + + g_kbd_reg0_pos = 0; + g_kbd_reg3_16bit = 0x602; +} + + +#define LEN_ADB_LOG 16 +STRUCT(Adb_log) { + word32 addr; + int val; + int state; +}; + +Adb_log g_adb_log[LEN_ADB_LOG]; +int g_adb_log_pos = 0; + +void +adb_log(word32 addr, int val) +{ + int pos; + + pos = g_adb_log_pos; + g_adb_log[pos].addr = addr; + g_adb_log[pos].val = val; + g_adb_log[pos].state = g_adb_state; + pos++; + if(pos >= LEN_ADB_LOG) { + pos = 0; + } + g_adb_log_pos = pos; +} + +void +show_adb_log(void) +{ + int pos; + int i; + + pos = g_adb_log_pos; + printf("ADB log pos: %d\n", pos); + for(i = 0; i < LEN_ADB_LOG; i++) { + pos--; + if(pos < 0) { + pos = LEN_ADB_LOG - 1; + } + printf("%d:%d: addr:%04x = %02x, st:%d\n", i, pos, + g_adb_log[pos].addr, g_adb_log[pos].val, + g_adb_log[pos].state); + } + printf("kbd: dev: %x, ctl: %x; mouse: dev: %x, ctl: %x\n", + g_kbd_dev_addr, g_kbd_ctl_addr, + g_mouse_dev_addr, g_mouse_ctl_addr); + printf("adb_data_int_sent: %d, adb_kbd_srq_sent: %d, mouse_int: %d\n", + g_adb_data_int_sent, g_adb_kbd_srq_sent, g_adb_mouse_int_sent); + printf("g_adb_state: %d, g_adb_interrupt_byte: %02x\n", + g_adb_state, g_adb_interrupt_byte); +} + +void +adb_error(void) +{ + halt_printf("Adb Error\n"); + + show_adb_log(); +} + + + +void +adb_add_kbd_srq() +{ + if(g_kbd_reg3_16bit & 0x200) { + /* generate SRQ */ + g_adb_interrupt_byte |= 0x08;; + if(!g_adb_kbd_srq_sent) { + g_adb_kbd_srq_sent = 1; + add_irq(); + } + } else { + printf("Got keycode but no kbd SRQ!\n"); + } +} + +void +adb_clear_kbd_srq() +{ + if(g_adb_kbd_srq_sent) { + remove_irq(); + g_adb_kbd_srq_sent = 0; + } + + /* kbd SRQ's are the only ones to handle now, so just clean it out */ + g_adb_interrupt_byte &= (~(0x08)); +} + +void +adb_add_data_int() +{ + if(g_c027_val & ADB_C027_DATA_INT) { + if(!g_adb_data_int_sent) { + g_adb_data_int_sent = 1; + add_irq(); + } + } +} + +void +adb_add_mouse_int() +{ + if(g_c027_val & ADB_C027_MOUSE_INT) { + if(!g_adb_mouse_int_sent) { + /* printf("Mouse int sent\n"); */ + g_adb_mouse_int_sent = 1; + add_irq(); + } + } +} + +void +adb_clear_data_int() +{ + if(g_adb_data_int_sent) { + remove_irq(); + g_adb_data_int_sent = 0; + } +} + +void +adb_clear_mouse_int() +{ + if(g_adb_mouse_int_sent) { + remove_irq(); + g_adb_mouse_int_sent = 0; + /* printf("Mouse int clear, button: %d\n", g_mouse_a2_button);*/ + } +} + + +void +adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2) +{ + word32 val; + int shift_amount; + int i; + + if((num_bytes >= 12) || (num_bytes >= MAX_ADB_DATA_PEND)) { + halt_printf("adb_send_bytes: %d is too many!\n", num_bytes); + } + + g_adb_state = ADB_SENDING_DATA; + g_adb_data_pending = num_bytes; + adb_add_data_int(); + + for(i = 0; i < num_bytes; i++) { + if(i < 4) { + val = val0; + } else if(i < 8) { + val = val1; + } else { + val = val2; + } + + shift_amount = 8*(3 - i); + g_adb_data[i] = (val >> shift_amount) & 0xff; + adb_printf("adb_send_bytes[%d] = %02x\n", i, g_adb_data[i]); + } +} + + +void +adb_send_1byte(word32 val) +{ + + if(g_adb_data_pending != 0) { + halt_printf("g_adb_data_pending: %d\n", g_adb_data_pending); + } + + adb_send_bytes(1, val << 24, 0, 0); +} + + + +void +adb_response_packet(int num_bytes, word32 val) +{ + + if(g_adb_data_pending != 0) { + halt_printf("adb_response_packet, but pending: %d\n", + g_adb_data_pending); + } + + g_adb_state = ADB_IDLE; + g_adb_data_pending = num_bytes; + g_adb_data[0] = val & 0xff; + g_adb_data[1] = (val >> 8) & 0xff; + g_adb_data[2] = (val >> 16) & 0xff; + g_adb_data[3] = (val >> 24) & 0xff; + if(num_bytes) { + g_adb_interrupt_byte |= 0x80 + num_bytes - 1; + } else { + g_adb_interrupt_byte |= 0x80; + } + + adb_printf("adb_response packet: %d: %08x\n", + num_bytes, val); + + adb_add_data_int(); +} + + +void +adb_kbd_reg0_data(int a2code, int is_up) +{ + if(g_kbd_reg0_pos >= MAX_ADB_KBD_REG3) { + /* too many keys, toss */ + halt_printf("Had to toss key: %02x, %d\n", a2code, is_up); + return; + } + + g_kbd_reg0_data[g_kbd_reg0_pos] = a2code + (is_up << 7); + + adb_printf("g_kbd_reg0_data[%d] = %02x\n", g_kbd_reg0_pos, + g_kbd_reg0_data[g_kbd_reg0_pos]); + + g_kbd_reg0_pos++; + + adb_add_kbd_srq(); +} + +void +adb_kbd_talk_reg0() +{ + word32 val0, val1; + word32 reg; + int num_bytes; + int num; + int i; + + num = 0; + val0 = g_kbd_reg0_data[0]; + val1 = g_kbd_reg0_data[1]; + + num_bytes = 0; + if(g_kbd_reg0_pos > 0) { + num_bytes = 2; + num = 1; + if((val0 & 0x7f) == 0x7f) { + /* reset */ + val1 = val0; + } else if(g_kbd_reg0_pos > 1) { + num = 2; + if((val1 & 0x7f) == 0x7f) { + /* If first byte some other key, don't */ + /* put RESET next! */ + num = 1; + val1 = 0xff; + } + } else { + val1 = 0xff; + } + } + + if(num) { + for(i = num; i < g_kbd_reg0_pos; i++) { + g_kbd_reg0_data[i-1] = g_kbd_reg0_data[i]; + } + g_kbd_reg0_pos -= num; + } + + reg = (val0 << 8) + val1; + + adb_printf("adb_kbd_talk0: %04x\n", reg); + + adb_response_packet(num_bytes, reg); + if(g_kbd_reg0_pos == 0) { + adb_clear_kbd_srq(); + } +} + +void +adb_set_config(word32 val0, word32 val1, word32 val2) +{ + int new_mouse; + int new_kbd; + int tmp1; + + new_mouse = val0 >> 4; + new_kbd = val0 & 0xf; + if(new_mouse != g_mouse_ctl_addr) { + printf("ADB config: mouse from %x to %x!\n", + g_mouse_ctl_addr, new_mouse); + adb_error(); + g_mouse_ctl_addr = new_mouse; + } + if(new_kbd != g_kbd_ctl_addr) { + printf("ADB config: kbd from %x to %x!\n", + g_kbd_ctl_addr, new_kbd); + adb_error(); + g_kbd_ctl_addr = new_kbd; + } + + + tmp1 = val2 >> 4; + if(tmp1 == 4) { + g_adb_repeat_delay = 0; + } else if(tmp1 < 4) { + g_adb_repeat_delay = (tmp1 + 1) * 15; + } else { + halt_printf("Bad ADB repeat delay: %02x\n", tmp1); + } + + tmp1 = val2 & 0xf; + if(g_rom_version >= 3) { + tmp1 = 9 - tmp1; + } + + switch(tmp1) { + case 0: + g_adb_repeat_rate = 1; + break; + case 1: + g_adb_repeat_rate = 2; + break; + case 2: + g_adb_repeat_rate = 3; + break; + case 3: + g_adb_repeat_rate = 3; + break; + case 4: + g_adb_repeat_rate = 4; + break; + case 5: + g_adb_repeat_rate = 5; + break; + case 6: + g_adb_repeat_rate = 7; + break; + case 7: + g_adb_repeat_rate = 15; + break; + case 8: + /* I don't know what this should be, ROM 03 uses it */ + g_adb_repeat_rate = 30; + break; + case 9: + /* I don't know what this should be, ROM 03 uses it */ + g_adb_repeat_rate = 60; + break; + default: + halt_printf("Bad repeat rate: %02x\n", tmp1); + } + +} + +void +adb_set_new_mode(word32 val) +{ + if(val & 0x03) { + printf("Disabling keyboard/mouse:%02x!\n", val); + } + + if(val & 0xa2) { + halt_printf("ADB set mode: %02x!\n", val); + adb_error(); + } + + g_adb_mode = val; +} + + +int +adb_read_c026() +{ + word32 ret; + int i; + + ret = 0; + switch(g_adb_state) { + case ADB_IDLE: + ret = g_adb_interrupt_byte; + g_adb_interrupt_byte = 0; + if(g_adb_kbd_srq_sent) { + g_adb_interrupt_byte |= 0x08; + } + if(g_adb_data_pending == 0) { + if(ret & 0x80) { + halt_printf("read_c026: ret:%02x, pend:%d\n", + ret, g_adb_data_pending); + } + adb_clear_data_int(); + } + if(g_adb_data_pending) { + if(g_adb_state != ADB_IN_CMD) { + g_adb_state = ADB_SENDING_DATA; + } + } + break; + case ADB_IN_CMD: + ret = 0; + break; + case ADB_SENDING_DATA: + ret = g_adb_data[0]; + for(i = 1; i < g_adb_data_pending; i++) { + g_adb_data[i-1] = g_adb_data[i]; + } + g_adb_data_pending--; + if(g_adb_data_pending <= 0) { + g_adb_data_pending = 0; + g_adb_state = ADB_IDLE; + adb_clear_data_int(); + } + break; + default: + halt_printf("Bad ADB state: %d!\n", g_adb_state); + adb_clear_data_int(); + break; + } + + adb_printf("Reading c026. Returning %02x, st: %02x, pend: %d\n", + ret, g_adb_state, g_adb_data_pending); + + adb_log(0xc026, ret); + return (ret & 0xff); +} + + +void +adb_write_c026(int val) +{ + word32 tmp; + int dev; + + adb_printf("Writing c026 with %02x\n", val); + adb_log(0x1c026, val); + + + switch(g_adb_state) { + case ADB_IDLE: + g_adb_cmd = val; + g_adb_cmd_so_far = 0; + g_adb_cmd_len = 0; + + dev = val & 0xf; + switch(val) { + case 0x01: /* Abort */ + adb_printf("Performing adb abort\n"); + /* adb_abort() */ + break; + case 0x03: /* Flush keyboard buffer */ + adb_printf("Flushing adb keyboard buffer\n"); + /* Do nothing */ + break; + case 0x04: /* Set modes */ + adb_printf("ADB set modes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x05: /* Clear modes */ + adb_printf("ADB clear modes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x06: /* Set config */ + adb_printf("ADB set config\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 3; + break; + case 0x07: /* Sync */ + adb_printf("Performing sync cmd!\n"); + g_adb_state = ADB_IN_CMD; + if(g_rom_version == 1) { + g_adb_cmd_len = 4; + } else { + g_adb_cmd_len = 8; + } + break; + case 0x08: /* Write mem */ + adb_printf("Starting write_mem cmd\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0x09: /* Read mem */ + adb_printf("Performing read_mem cmd!\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0x0a: /* Read modes byte */ + printf("Performing read_modes cmd!\n"); + /* set_halt(1); */ + adb_send_1byte(g_adb_mode); + break; + case 0x0b: /* Read config bytes */ + printf("Performing read_configs cmd!\n"); + tmp = (g_mouse_ctl_addr << 20) + + (g_kbd_ctl_addr << 16) + + (g_adb_char_set << 12) + + (g_adb_layout_lang << 8) + + (g_adb_repeat_info << 0); + tmp = (0x82U << 24) + tmp; + adb_send_bytes(4, tmp, 0, 0); + break; + case 0x0d: /* Get Version */ + adb_printf("Performing get_version cmd!\n"); + val = 0; + if(g_rom_version == 1) { + /* ROM 01 = revision 5 */ + val = 5; + } else { + /* ROM 03 checks for rev >= 6 */ + val = 6; + } + adb_send_1byte(val); + break; + case 0x0e: /* Read avail char sets */ + adb_printf("Performing read avail char sets cmd!\n"); + adb_send_bytes(2, /* just 2 bytes */ + 0x08000000, /* number of ch sets=0x8 */ + 0, 0); + /* set_halt(1); */ + break; + case 0x0f: /* Read avail kbd layouts */ + adb_printf("Performing read avail kbd layouts cmd!\n"); + adb_send_bytes(0x2, /* number of kbd layouts=0xa */ + 0x0a000000, 0, 0); + /* set_halt(1); */ + break; + case 0x10: /* Reset */ + printf("ADB reset, cmd 0x10\n"); + do_reset(); + break; + case 0x11: /* Send ADB keycodes */ + adb_printf("Sending ADB keycodes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x12: /* ADB cmd 12: ROM 03 only! */ + if(g_rom_version >= 3) { + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + } else { + printf("ADB cmd 12, but not ROM 3!\n"); + adb_error(); + } + break; + case 0x13: /* ADB cmd 13: ROM 03 only! */ + if(g_rom_version >= 3) { + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + } else { + printf("ADB cmd 13, but not ROM 3!\n"); + adb_error(); + } + break; + case 0x73: /* Disable SRQ device 3: mouse */ + adb_printf("Disabling Mouse SRQ's (device 3)\n"); + /* HACK HACK...should deal with SRQs on mouse */ + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* Listen dev x reg 3 */ + adb_printf("Sending data to dev %x reg 3\n", dev); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + /* Talk dev x reg 0 */ + adb_printf("Performing talk dev %x reg 0\n", dev); + if(dev == g_kbd_dev_addr) { + adb_kbd_talk_reg0(); + } else { + printf("Unknown talk dev %x reg 0!\n", dev); + /* send no data, on SRQ, system polls devs */ + /* so we don't want to send anything */ + adb_error(); + } + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + /* Talk dev x reg 3 */ + adb_printf("Performing talk dev %x reg 3\n", dev); + if(dev == g_kbd_dev_addr) { + adb_response_packet(2, g_kbd_reg3_16bit); + } else { + printf("Performing talk dev %x reg 3!!\n", dev); + adb_error(); + } + break; + default: + halt_printf("ADB ucontroller cmd %02x unknown!\n", val); + /* The Gog's says ACS Demo 2 has a bug and writes to */ + /* c026 */ + break; + } + break; + case ADB_IN_CMD: + adb_printf("Setting byte %d of cmd %02x to %02x\n", + g_adb_cmd_so_far, g_adb_cmd, val); + + g_adb_cmd_data[g_adb_cmd_so_far] = val; + g_adb_cmd_so_far++; + if(g_adb_cmd_so_far >= g_adb_cmd_len) { + adb_printf("Finished cmd %02x\n", g_adb_cmd); + do_adb_cmd(); + } + + break; + default: + printf("adb_state: %02x is unknown! Setting it to ADB_IDLE\n", + g_adb_state); + g_adb_state = ADB_IDLE; + adb_error(); + halt_on_all_c027 = 1; + break; + } + return; +} + +void +do_adb_cmd() +{ + int dev; + int new_kbd; + int addr; + int val; + + dev = g_adb_cmd & 0xf; + + g_adb_state = ADB_IDLE; + + switch(g_adb_cmd) { + case 0x04: /* Set modes */ + adb_printf("Performing ADB set mode: OR'ing in %02x\n", + g_adb_cmd_data[0]); + + val = g_adb_cmd_data[0] | g_adb_mode; + adb_set_new_mode(val); + + break; + case 0x05: /* clear modes */ + adb_printf("Performing ADB clear mode: AND'ing in ~%02x\n", + g_adb_cmd_data[0]); + + val = g_adb_cmd_data[0]; + val = g_adb_mode & (~val); + adb_set_new_mode(val); + break; + case 0x06: /* Set config */ + adb_printf("Set ADB config to %02x %02x %02x\n", + g_adb_cmd_data[0], g_adb_cmd_data[1],g_adb_cmd_data[2]); + + adb_set_config(g_adb_cmd_data[0], g_adb_cmd_data[1], + g_adb_cmd_data[2]); + + break; + case 0x07: /* SYNC */ + adb_printf("Performing ADB SYNC\n"); + adb_printf("data: %02x %02x %02x %02x\n", + g_adb_cmd_data[0], g_adb_cmd_data[1], g_adb_cmd_data[2], + g_adb_cmd_data[3]); + + adb_set_new_mode(g_adb_cmd_data[0]); + adb_set_config(g_adb_cmd_data[1], g_adb_cmd_data[2], + g_adb_cmd_data[3]); + + if(g_rom_version >= 3) { + adb_printf(" and cmd12:%02x %02x cmd13:%02x %02x\n", + g_adb_cmd_data[4], g_adb_cmd_data[5], + g_adb_cmd_data[6], g_adb_cmd_data[7]); + } + break; + case 0x08: /* Write mem */ + addr = g_adb_cmd_data[0]; + val = g_adb_cmd_data[1]; + write_adb_ram(addr, val); + break; + case 0x09: /* Read mem */ + addr = (g_adb_cmd_data[1] << 8) + g_adb_cmd_data[0]; + adb_printf("Performing mem read to addr %04x\n", addr); + adb_send_1byte(read_adb_ram(addr)); + break; + case 0x11: /* Send ADB keycodes */ + val = g_adb_cmd_data[0]; + adb_printf("Performing send ADB keycodes: %02x\n", val); + adb_virtual_key_update(val & 0x7f, val >> 7); + break; + case 0x12: /* ADB cmd12 */ + adb_printf("Performing ADB cmd 12\n"); + adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], + g_adb_cmd_data[1]); + break; + case 0x13: /* ADB cmd13 */ + adb_printf("Performing ADB cmd 13\n"); + adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], + g_adb_cmd_data[1]); + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* Listen dev x reg 3 */ + if(dev == g_kbd_dev_addr) { + if(g_adb_cmd_data[1] == 0xfe) { + /* change keyboard addr? */ + new_kbd = g_adb_cmd_data[0] & 0xf; + if(new_kbd != dev) { + printf("Moving kbd to dev %x!\n", + new_kbd); + adb_error(); + } + g_kbd_dev_addr = new_kbd; + } else if(g_adb_cmd_data[1] != 1) { + /* see what new device handler id is */ + printf("KBD listen to dev %x reg 3: 1:%02x\n", + dev, g_adb_cmd_data[1]); + adb_error(); + } + if(g_adb_cmd_data[0] != (word32)g_kbd_dev_addr) { + /* see if app is trying to change addr */ + printf("KBD listen to dev %x reg 3: 0:%02x!\n", + dev, g_adb_cmd_data[0]); + adb_error(); + } + g_kbd_reg3_16bit = ((g_adb_cmd_data[0] & 0xf) << 12) + + (g_kbd_reg3_16bit & 0x0fff); + } else if(dev == g_mouse_dev_addr) { + if(g_adb_cmd_data[0] != (word32)dev) { + /* see if app is trying to change mouse addr */ + printf("MOUS listen to dev %x reg3: 0:%02x!\n", + dev, g_adb_cmd_data[0]); + adb_error(); + } + if(g_adb_cmd_data[1] != 1 && g_adb_cmd_data[1] != 2) { + /* see what new device handler id is */ + printf("MOUS listen to dev %x reg 3: 1:%02x\n", + dev, g_adb_cmd_data[1]); + adb_error(); + } + } else { + printf("Listen cmd to dev %x reg3????\n", dev); + printf("data0: %02x, data1: %02x ????\n", + g_adb_cmd_data[0], g_adb_cmd_data[1]); + adb_error(); + } + break; + default: + printf("Doing adb_cmd %02x: UNKNOWN!\n", g_adb_cmd); + break; + } +} + + +int +adb_read_c027() +{ + word32 ret; + + if(halt_on_all_c027) { + halt_printf("halting on all c027 reads!\n"); + } + + if(g_c027_val & (~ADB_C027_NEG_MASK)) { + halt_printf("read_c027: g_c027_val: %02x\n", g_c027_val); + } + + ret = (g_c027_val & ADB_C027_NEG_MASK); + + if(g_adb_mouse_valid_data) { + ret |= ADB_C027_MOUSE_DATA; + } + + if(g_adb_interrupt_byte != 0) { + ret |= ADB_C027_DATA_VALID; + } else if(g_adb_data_pending > 0) { + if((g_adb_state != ADB_IN_CMD)) { + ret |= ADB_C027_DATA_VALID; + } + } + + if(g_adb_mouse_coord) { + ret |= ADB_C027_MOUSE_COORD; + } + +#if 0 + adb_printf("Read c027: %02x, int_byte: %02x, d_pend: %d\n", + ret, g_adb_interrupt_byte, g_adb_data_pending); +#endif + +#if 0 + adb_log(0xc027, ret); +#endif + return ret; +} + +void +adb_write_c027(int val) +{ + word32 old_val; + word32 new_int; + word32 old_int; + + adb_printf("Writing c027 with %02x\n", val); + adb_log(0x1c027, val); + + + old_val = g_c027_val; + + g_c027_val = (val & ADB_C027_NEG_MASK); + new_int = g_c027_val & ADB_C027_MOUSE_INT; + old_int = old_val & ADB_C027_MOUSE_INT; + if(!new_int && old_int) { + adb_clear_mouse_int(); + } + + new_int = g_c027_val & ADB_C027_DATA_INT; + old_int = old_val & ADB_C027_DATA_INT; + if(!new_int && old_int) { + /* ints were on, now off */ + adb_clear_data_int(); + } + + if(g_c027_val & ADB_C027_KBD_INT) { + halt_printf("Can't support kbd interrupts!\n"); + } + + return; +} + +int +read_adb_ram(word32 addr) +{ + int val; + + adb_printf("Reading adb ram addr: %02x\n", addr); + + if(addr >= 0x100) { + if(addr >= 0x1000 && addr < 0x2000) { + /* ROM self-test checksum */ + if(addr == 0x1400) { + val = 0x72; + } else if(addr == 0x1401) { + val = 0xf7; + } else { + val = 0; + } + } else { + printf("adb ram addr out of range: %04x!\n", addr); + val = 0; + } + } else { + val = adb_memory[addr]; + if((addr == 0xb) && (g_rom_version == 1)) { + // read special key state byte for Out of This World + val = (g_c025_val >> 1) & 0x43; + val |= (g_c025_val << 2) & 0x4; + val |= (g_c025_val >> 2) & 0x10; + } + if((addr == 0xc) && (g_rom_version >= 3)) { + // read special key state byte for Out of This World + val = g_c025_val & 0xc7; + printf("val is %02x\n", val); + } + } + + adb_printf("adb_ram returning %02x\n", val); + return val; +} + +void +write_adb_ram(word32 addr, int val) +{ + + adb_printf("Writing adb_ram addr: %02x: %02x\n", addr, val); + + if(addr >= 0x100) { + printf("write adb_ram addr: %02x: %02x!\n", addr, val); + adb_error(); + } else { + adb_memory[addr] = val; + } +} + +int +update_mouse(int x, int y, int button_states, int buttons_valid) +{ + int button1_changed; + int mouse_moved; + int unhide; + int pos; + int i; + + unhide = 0; + if(x < 0) { + x = 0; + unhide = 1; + } + if(x >= 640) { + x = 639; + unhide = 1; + } + if(y < 0) { + y = 0; + unhide = 1; + } + if(y >= 400) { + y = 399; + unhide = 1; + } + + + g_unhide_pointer = unhide && !g_warp_pointer; + + if(!g_warp_pointer) { + if(g_hide_pointer && g_unhide_pointer) { + /* cursor has left a2 window, show it */ + g_hide_pointer = 0; + x_hide_pointer(0); + } + if((g_num_lines_prev_superhires == 200) && + (g_num_lines_prev_superhires640 == 0) && + ((g_slow_memory_ptr[0x19d00] & 0x80) == 0)) { + // In 320-mode superhires, cut mouse range in half + x = x >> 1; + } + y = y >> 1; + } + +#if 0 + printf("Update Mouse called with buttons:%d x,y:%d,%d, fifo:%d,%d, " + " a2: %d,%d\n", buttons_valid, x, y, + g_mouse_fifo_x[0], g_mouse_fifo_y[0], + g_mouse_a2_x, g_mouse_a2_y); +#endif + + if((buttons_valid < 0) && g_warp_pointer) { + /* Warping the pointer causes it to jump here...this is not */ + /* real motion, just update info and get out */ + g_mouse_a2_x += (x - g_mouse_fifo_x[0]); + g_mouse_a2_y += (y - g_mouse_fifo_y[0]); + g_mouse_fifo_x[0] = x; + g_mouse_fifo_y[0] = y; + return 0; + } + +#if 0 + printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n", + g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo_x[0], + g_mouse_fifo_y[0], g_mouse_a2_x, g_mouse_a2_y); +#endif + + mouse_moved = (g_mouse_fifo_x[0] != x) || (g_mouse_fifo_y[0] != y); + + g_mouse_a2_x += g_mouse_warp_x; + g_mouse_a2_y += g_mouse_warp_y; + g_mouse_fifo_x[0] = x; + g_mouse_fifo_y[0] = y; + g_mouse_warp_x = 0; + g_mouse_warp_y = 0; + + button1_changed = (buttons_valid & 1) && + ((button_states & 1) != (g_mouse_fifo_buttons[0] & 1)); + + if((button_states & 4) && !(g_mouse_fifo_buttons[0] & 4) && + (buttons_valid & 4)) { + /* right button pressed */ + adb_increment_speed(); + } + if((button_states & 2) && !(g_mouse_fifo_buttons[0] & 2) && + (buttons_valid & 2)) { + /* middle button pressed */ + halt2_printf("Middle button pressed\n"); + } + + pos = g_mouse_fifo_pos; + if((pos < (ADB_MOUSE_FIFO - 2)) && button1_changed) { + /* copy delta to overflow, set overflow */ + /* overflow ensures the mouse button state is precise at */ + /* button up/down times. Using a mouse event list where */ + /* deltas accumulate until a button change would work, too */ + for(i = pos; i >= 0; i--) { + g_mouse_fifo_x[i + 1] = g_mouse_fifo_x[i]; + g_mouse_fifo_y[i + 1] = g_mouse_fifo_y[i]; + g_mouse_fifo_buttons[i + 1] = g_mouse_fifo_buttons[i]&1; + } + g_mouse_fifo_pos = pos + 1; + } + + g_mouse_fifo_buttons[0] = (button_states & buttons_valid) | + (g_mouse_fifo_buttons[0] & ~buttons_valid); + + if(mouse_moved || button1_changed) { + if( (g_mouse_ctl_addr == g_mouse_dev_addr) && + ((g_adb_mode & 0x2) == 0)) { + g_adb_mouse_valid_data = 1; + adb_add_mouse_int(); + } + } + + return mouse_moved; +} + +int +mouse_read_c024(double dcycs) +{ + word32 ret; + word32 tool_start; + int em_active; + int target_x, target_y; + int delta_x, delta_y; + int a2_x, a2_y; + int mouse_button; + int clamped; + int pos; + + if(((g_adb_mode & 0x2) != 0) || (g_mouse_dev_addr != g_mouse_ctl_addr)){ + /* mouse is off, return 0, or mouse is not autopoll */ + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + return 0; + } + + pos = g_mouse_fifo_pos; + target_x = g_mouse_fifo_x[pos]; + target_y = g_mouse_fifo_y[pos]; + mouse_button = (g_mouse_fifo_buttons[pos] & 1); + delta_x = target_x - g_mouse_a2_x; + delta_y = target_y - g_mouse_a2_y; + + clamped = 0; + if(delta_x > 0x3f) { + delta_x = 0x3f; + clamped = 1; + } else if(delta_x < -0x3f) { + delta_x = -0x3f; + clamped = 1; + } + if(delta_y > 0x3f) { + delta_y = 0x3f; + clamped = 1; + } else if(delta_y < -0x3f) { + delta_y = -0x3f; + clamped = 1; + } + + if(pos > 0) { + /* peek into next entry's button info if we are not clamped */ + /* and we're returning the y-coord */ + if(!clamped && g_adb_mouse_coord) { + mouse_button = g_mouse_fifo_buttons[pos - 1] & 1; + } + } + + if(g_adb_mouse_coord) { + /* y coord */ + delta_x = 0; /* clear unneeded x delta */ + } else { + delta_y = 0; /* clear unneeded y delta */ + } + + + adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x100e9], g_slow_memory_ptr[0x100ea], + g_slow_memory_ptr[0x100eb], g_slow_memory_ptr[0x100ec]); + adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], + g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); + + /* Update event manager internal state */ + tool_start = (g_slow_memory_ptr[0x103ca] << 16) + + (g_slow_memory_ptr[0x103c9] << 8) + + g_slow_memory_ptr[0x103c8]; + + em_active = 0; + if((tool_start >= 0x20000) && (tool_start < (g_mem_size_total - 28)) ) { + /* seems to be valid ptr to addr of mem space for tools */ + /* see if event manager appears to be active */ + em_active = g_memory_ptr[tool_start + 6*4] + + (g_memory_ptr[tool_start + 6*4 + 1] << 8); + if(g_warp_pointer) { + em_active = 0; + } + } + + a2_x = g_mouse_a2_x; + a2_y = g_mouse_a2_y; + + if(em_active) { + if((!g_hide_pointer) && (g_num_lines_prev_superhires == 200) && + !g_unhide_pointer) { + /* if super-hires and forcing tracking, then hide */ + g_hide_pointer = 1; + x_hide_pointer(1); + } + if(g_adb_mouse_coord == 0) { + /* update x coord values */ + g_slow_memory_ptr[0x47c] = a2_x & 0xff; + g_slow_memory_ptr[0x57c] = a2_x >> 8; + g_memory_ptr[0x47c] = a2_x & 0xff; + g_memory_ptr[0x57c] = a2_x >> 8; + + g_slow_memory_ptr[0x10190] = a2_x & 0xff; + g_slow_memory_ptr[0x10192] = a2_x >> 8; + } else { + g_slow_memory_ptr[0x4fc] = a2_y & 0xff; + g_slow_memory_ptr[0x5fc] = a2_y >> 8; + g_memory_ptr[0x4fc] = a2_y & 0xff; + g_memory_ptr[0x5fc] = a2_y >> 8; + + g_slow_memory_ptr[0x10191] = a2_y & 0xff; + g_slow_memory_ptr[0x10193] = a2_y >> 8; + } + } else { + if(g_hide_pointer && !g_warp_pointer) { + g_hide_pointer = 0; + x_hide_pointer(0); + } + } + + ret = ((!mouse_button) << 7) + ((delta_x | delta_y) & 0x7f); + if(g_adb_mouse_coord) { + g_mouse_a2_button = mouse_button; /* y coord has button*/ + } else { + ret |= 0x80; /* mouse button not down on x coord rd */ + } + + a2_x += delta_x; + a2_y += delta_y; + g_mouse_a2_x = a2_x; + g_mouse_a2_y = a2_y; + if(g_mouse_fifo_pos) { + if((target_x == a2_x) && (target_y == a2_y) && + (g_mouse_a2_button == mouse_button)) { + g_mouse_fifo_pos--; + } + } + + + adb_printf("Read c024, mouse is_y:%d, %02x, vbl:%08x, dcyc:%f, em:%d\n", + g_adb_mouse_coord, ret, g_vbl_count, dcycs, em_active); + adb_printf("...mouse targ_x:%d,%d delta_x,y:%d,%d fifo:%d, a2:%d,%d\n", + target_x, target_y, delta_x, delta_y, g_mouse_fifo_pos, + a2_x, a2_y); + adb_printf(" post a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], + g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); + + if((g_mouse_fifo_pos == 0) && (g_mouse_fifo_x[0] == a2_x) && + (g_mouse_fifo_y[0] == a2_y) && + ((g_mouse_fifo_buttons[0] & 1) == g_mouse_a2_button)) { + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + } + + g_adb_mouse_coord = !g_adb_mouse_coord; + return ret; +} + +void +adb_key_event(int a2code, int is_up) +{ + word32 special; + word32 vbl_count; + int key; + int hard_key; + int pos; + int tmp_ascii; + int ascii; + + if(is_up) { + adb_printf("adb_key_event, key:%02x, is up, g_key_down: %02x\n", + a2code, g_key_down); + } + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("add_key_event: a2code: %04x!\n", a2code); + return; + } + + if(!is_up && a2code == 0x35) { + /* ESC pressed, see if ctrl & cmd key down */ + if(CTRL_DOWN && CMD_DOWN) { + /* Desk mgr int */ + printf("Desk mgr int!\n"); + + g_adb_interrupt_byte |= 0x20; + adb_add_data_int(); + } + } + + /* convert key to ascii, if possible */ + hard_key = 0; + if(a2_key_to_ascii[a2code][1] & 0xef00) { + /* special key */ + } else { + /* we have ascii */ + hard_key = 1; + } + + pos = 1; + ascii = a2_key_to_ascii[a2code][1]; + if(CAPS_LOCK_DOWN && (ascii >= 'a' && ascii <= 'z')) { + pos = 2; + if(SHIFT_DOWN && (g_adb_mode & 0x40)) { + /* xor shift mode--capslock and shift == lowercase */ + pos = 1; + } + } else if(SHIFT_DOWN) { + pos = 2; + } + + ascii = a2_key_to_ascii[a2code][pos]; + if(CTRL_DOWN) { + tmp_ascii = a2_key_to_ascii[a2code][3]; + if(tmp_ascii >= 0) { + ascii = tmp_ascii; + } + } + key = (ascii & 0x7f) + 0x80; + + special = (ascii >> 8) & 0xff; + if(ascii < 0) { + printf("ascii1: %d, a2code: %02x, pos: %d\n", ascii,a2code,pos); + ascii = 0; + special = 0; + } + + + if(!is_up) { + if(hard_key) { + g_kbd_buf[g_kbd_chars_buffered] = key; + g_kbd_chars_buffered++; + if(g_kbd_chars_buffered >= MAX_KBD_BUF) { + g_kbd_chars_buffered = MAX_KBD_BUF - 1; + } + g_key_down = 1; + g_a2code_down = a2code; + + /* first key down, set up autorepeat */ + vbl_count = g_vbl_count; + if(g_config_control_panel) { + vbl_count = g_cfg_vbl_count; + } + g_adb_repeat_vbl = vbl_count + g_adb_repeat_delay; + if(g_adb_repeat_delay == 0) { + g_key_down = 0; + } + g_hard_key_down = 1; + } + + g_c025_val = g_c025_val | special; + adb_printf("new c025_or: %02x\n", g_c025_val); + } else { + if(hard_key && (a2code == g_a2code_down)) { + g_hard_key_down = 0; + /* Turn off repeat */ + g_key_down = 0; + } + + g_c025_val = g_c025_val & (~ special); + adb_printf("new c025_and: %02x\n", g_c025_val); + } + + if(g_key_down) { + g_c025_val = g_c025_val & (~0x20); + } else { + /* If no hard key down, set update mod latch */ + g_c025_val = g_c025_val | 0x20; + } + +} + +word32 +adb_read_c000() +{ + word32 vbl_count; + + if( ((g_kbd_buf[0] & 0x80) == 0) && (g_key_down == 0)) { + /* nothing happening, just get out */ + return g_kbd_buf[0]; + } + if(g_kbd_buf[0] & 0x80) { + /* got one */ + if((g_kbd_read_no_update++ > 5) && (g_kbd_chars_buffered > 1)) { + /* read 5 times, keys pending, let's move it along */ + printf("Read %02x 3 times, tossing\n", g_kbd_buf[0]); + adb_access_c010(); + } + } else { + vbl_count = g_vbl_count; + if(g_config_control_panel) { + vbl_count = g_cfg_vbl_count; + } + if(g_key_down && vbl_count >= g_adb_repeat_vbl) { + /* repeat the g_key_down */ + g_c025_val |= 0x8; + adb_key_event(g_a2code_down, 0); + g_adb_repeat_vbl = vbl_count + g_adb_repeat_rate; + } + } + + return g_kbd_buf[0]; +} + +word32 +adb_access_c010() +{ + int tmp; + int i; + + g_kbd_read_no_update = 0; + + tmp = g_kbd_buf[0] & 0x7f; + g_kbd_buf[0] = tmp; + + tmp = tmp | (g_hard_key_down << 7); + if(g_kbd_chars_buffered) { + for(i = 1; i < g_kbd_chars_buffered; i++) { + g_kbd_buf[i - 1] = g_kbd_buf[i]; + } + g_kbd_chars_buffered--; + } + + g_c025_val = g_c025_val & (~ (0x08)); + + return tmp; +} + +word32 +adb_read_c025() +{ + return g_c025_val; +} + +int +adb_is_cmd_key_down() +{ + return CMD_DOWN; +} + +int +adb_is_option_key_down() +{ + return OPTION_DOWN; +} + +void +adb_increment_speed() +{ + const char *str; + + g_limit_speed++; + if(g_limit_speed > 3) { + g_limit_speed = 0; + } + + str = ""; + switch(g_limit_speed) { + case 0: + str = "...as fast as possible!"; + break; + case 1: + str = "...1.024MHz!"; + break; + case 2: + str = "...2.8MHz!"; + break; + case 3: + str = "...8.0MHz!"; + break; + } + printf("Toggling g_limit_speed to %d%s\n", g_limit_speed, str); +} + +void +adb_physical_key_update(int a2code, int is_up) +{ + int autopoll; + int special; + int tmp; + + /* this routine called by xdriver to pass raw codes--handle */ + /* ucontroller and ADB bus protocol issues here */ + /* if autopoll on, pass it on through to c025,c000 regs */ + /* else only put it in kbd reg 3, and pull SRQ if needed */ + + adb_printf("adb_phys_key_update: %02x, %d\n", a2code, is_up); + + adb_printf("Handle a2code: %02x, is_up: %d\n", a2code, is_up); + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("a2code: %04x!\n", a2code); + return; + } + + /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards */ + if(a2code >= 0x7b && a2code <= 0x7e) { + a2code = a2code - 0x40; + } + + /* Now check for special keys (function keys, etc) */ + tmp = a2_key_to_ascii[a2code][1]; + special = 0; + if((tmp & 0xf000) == 0x8000) { + /* special function key */ + special = tmp & 0xff; + switch(special) { + case 0x01: /* F1 - remap to cmd */ + a2code = 0x37; + special = 0; + break; + case 0x02: /* F2 - remap to option */ + a2code = 0x3a; + special = 0; + break; + case 0x03: /* F3 - remap to escape for OS/2 */ + a2code = 0x35; + special = 0; + break; + case 0x0c: /* F12 - remap to reset */ + a2code = 0x7f; + special = 0; + break; + default: + break; + } + } + + /* Only process reset requests here */ + if(is_up == 0 && a2code == 0x7f && CTRL_DOWN) { + /* Reset pressed! */ + printf("Reset pressed since CTRL_DOWN: %d\n", CTRL_DOWN); + do_reset(); + return; + } + + if(special && !is_up) { + switch(special) { + case 0x04: /* F4 - Emulator config panel */ + g_config_control_panel = !g_config_control_panel; + break; + case 0x06: /* F6 - emulator speed */ + if(SHIFT_DOWN) { + halt2_printf("Shift-F6 pressed\n"); + } else { + adb_increment_speed(); + } + break; + case 0x07: /* F7 - fast disk emul */ + g_fast_disk_emul = !g_fast_disk_emul; + printf("g_fast_disk_emul is now %d\n", + g_fast_disk_emul); + break; + case 0x08: /* F8 - warp pointer */ + g_warp_pointer = !g_warp_pointer; + if(g_hide_pointer != g_warp_pointer) { + g_hide_pointer = g_warp_pointer; + x_hide_pointer(g_hide_pointer); + } + break; + case 0x09: /* F9 - swap paddles */ + if(SHIFT_DOWN) { + g_swap_paddles = !g_swap_paddles; + printf("Swap paddles is now: %d\n", + g_swap_paddles); + } else { + g_invert_paddles = !g_invert_paddles; + printf("Invert paddles is now: %d\n", + g_invert_paddles); + } + break; + case 0x0a: /* F10 - change a2vid paletter */ + change_a2vid_palette((g_a2vid_palette + 1) & 0xf); + break; + case 0x0b: /* F11 - full screen */ + /* g_fullscreen = !g_fullscreen; */ + /* x_full_screen(g_full_screen); */ + break; + } + + return; + } + + autopoll = 1; + if(g_adb_mode & 1) { + /* autopoll is explicitly off */ + autopoll = 0; + } + if(g_kbd_dev_addr != g_kbd_ctl_addr) { + /* autopoll is off because ucontroller doesn't know kbd moved */ + autopoll = 0; + } + if(g_config_control_panel) { + /* always do autopoll */ + autopoll = 1; + } + + + if(is_up) { + if(!autopoll) { + /* no auto keys, generate SRQ! */ + adb_kbd_reg0_data(a2code, is_up); + } else { + adb_virtual_key_update(a2code, is_up); + } + } else { + if(!autopoll) { + /* no auto keys, generate SRQ! */ + adb_kbd_reg0_data(a2code, is_up); + } else { + /* was up, now down */ + adb_virtual_key_update(a2code, is_up); + } + } +} + +void +adb_virtual_key_update(int a2code, int is_up) +{ + int i; + int bitpos; + word32 mask; + + adb_printf("Virtual handle a2code: %02x, is_up: %d\n", a2code, is_up); + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("a2code: %04x!\n", a2code); + return; + } + + i = (a2code >> 5) & 3; + bitpos = a2code & 0x1f; + mask = (1 << bitpos); + + if(is_up) { + if(g_virtual_key_up[i] & mask) { + /* already up, do nothing */ + } else { + g_virtual_key_up[i] |= mask; + adb_key_event(a2code, is_up); + } + } else { + if(g_virtual_key_up[i] & mask) { + g_virtual_key_up[i] &= (~mask); + adb_key_event(a2code, is_up); + } + } +} + +void +adb_kbd_repeat_off() +{ + g_key_down = 0; +} diff --git a/src/adb.h b/src/adb.h new file mode 100644 index 0000000..857aa33 --- /dev/null +++ b/src/adb.h @@ -0,0 +1,160 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_adb_h[] = "@(#)$KmKId: adb.h,v 1.9 2002-11-19 03:10:38-05 kadickey Exp $"; + +#include "defc.h" + +/* Format: a2code, ascii if no shift, ascii if shift, ascii if ctl */ +const int a2_key_to_ascii[][4] = { + { 0x00, 'a', 'A', 0x01 }, + { 0x01, 's', 'S', 0x13 }, + { 0x02, 'd', 'D', 0x04 }, + { 0x03, 'f', 'F', 0x06 }, + { 0x04, 'h', 'H', 0x08 }, + { 0x05, 'g', 'G', 0x07 }, + { 0x06, 'z', 'Z', 0x1a }, + { 0x07, 'x', 'X', 0x18 }, + + { 0x08, 'c', 'C', 0x03 }, + { 0x09, 'v', 'V', 0x16 }, + { 0x0a, -1, -1, -1 }, + { 0x0b, 'b', 'B', 0x02 }, + { 0x0c, 'q', 'Q', 0x11 }, + { 0x0d, 'w', 'W', 0x17 }, + { 0x0e, 'e', 'E', 0x05 }, + { 0x0f, 'r', 'R', 0x12 }, + + { 0x10, 'y', 'Y', 0x19 }, + { 0x11, 't', 'T', 0x14 }, + { 0x12, '1', '!', -1 }, + { 0x13, '2', '@', 0x00 }, + { 0x14, '3', '#', -1 }, + { 0x15, '4', '$', -1 }, + { 0x16, '6', '^', 0x1e }, + { 0x17, '5', '%', -1 }, + + { 0x18, '=', '+', -1 }, + { 0x19, '9', '(', -1 }, + { 0x1a, '7', '&', -1 }, + { 0x1b, '-', '_', 0x1f }, + { 0x1c, '8', '*', -1 }, + { 0x1d, '0', ')', -1 }, + { 0x1e, ']', '}', 0x1d }, + { 0x1f, 'o', 'O', 0x0f }, + + { 0x20, 'u', 'U', 0x15 }, + { 0x21, '[', '{', 0x1b }, + { 0x22, 'i', 'I', 0x09 }, + { 0x23, 'p', 'P', 0x10 }, + { 0x24, 0x0d, 0x0d, -1 }, /* return */ + { 0x25, 'l', 'L', 0x0c }, + { 0x26, 'j', 'J', 0x0a }, + { 0x27, 0x27, '"', -1 }, /* single quote */ + + { 0x28, 'k', 'K', 0x0b }, + { 0x29, ';', ':', -1 }, + { 0x2a, 0x5c, '|', 0x1c }, /* \, | */ + { 0x2b, ',', '<', -1 }, + { 0x2c, '/', '?', 0x7f }, + { 0x2d, 'n', 'N', 0x0e }, + { 0x2e, 'm', 'M', 0x0d }, + { 0x2f, '.', '>', -1 }, + + { 0x30, 0x09, 0x09, -1 }, /* tab */ + { 0x31, ' ', ' ', -1 }, + { 0x32, '`', '~', -1 }, + { 0x33, 0x7f, 0x7f, -1 }, /* Delete */ + { 0x34, -1, -1, -1 }, + { 0x35, 0x1b, 0x1b, -1 }, /* Esc */ + { 0x36, 0x0200, 0x0200, -1 }, /* control */ + { 0x37, 0x8000, 0x8000, -1 }, /* Command */ + + { 0x38, 0x0100, 0x0100, -1 }, /* shift */ + { 0x39, 0x0400, 0x0400, -1 }, /* caps lock */ + { 0x3a, 0x4000, 0x4000, -1 }, /* Option */ + { 0x3b, 0x08, 0x08, -1 }, /* left */ + { 0x3c, 0x15, 0x15, -1 }, /* right */ + { 0x3d, 0x0a, 0x0a, -1 }, /* down */ + { 0x3e, 0x0b, 0x0b, -1 }, /* up arrow */ + { 0x3f, -1, -1, -1 }, + + { 0x40, -1, -1, -1 }, + { 0x41, 0x102e, 0x102e, -1 }, /* keypad . */ + { 0x42, -1, -1, -1 }, + { 0x43, 0x102a, 0x102a, -1 }, /* keypad * */ + { 0x44, -1, -1, -1 }, + { 0x45, 0x102b, 0x102b, -1 }, /* keypad + */ + { 0x46, -1, -1, -1 }, + { 0x47, 0x1018, 0x1018, -1 }, /* keypad Clear */ + + { 0x48, -1, -1, -1 }, + { 0x49, -1, -1, -1 }, + { 0x4a, -1, -1, -1 }, + { 0x4b, 0x102f, 0x102f, -1 }, /* keypad / */ + { 0x4c, 0x100d, 0x100d, -1 }, /* keypad enter */ + { 0x4d, -1, -1, -1 }, + { 0x4e, 0x102d, 0x102d, -1 }, /* keypad - */ + { 0x4f, -1, -1, -1 }, + + { 0x50, -1, -1, -1 }, + { 0x51, 0x103d, 0x103d, -1 }, /* keypad = */ + { 0x52, 0x1030, 0x1030, -1 }, /* keypad 0 */ + { 0x53, 0x1031, 0x1031, -1 }, /* keypad 1 */ + { 0x54, 0x1032, 0x1032, -1 }, /* keypad 2 */ + { 0x55, 0x1033, 0x1033, -1 }, /* keypad 3 */ + { 0x56, 0x1034, 0x1034, -1 }, /* keypad 4 */ + { 0x57, 0x1035, 0x1035, -1 }, /* keypad 5 */ + + { 0x58, 0x1036, 0x1036, -1 }, /* keypad 6 */ + { 0x59, 0x1037, 0x1037, -1 }, /* keypad 7 */ + { 0x5a, -1, -1, -1 }, + { 0x5b, 0x1038, 0x1038, -1 }, /* keypad 8 */ + { 0x5c, 0x1039, 0x1039, -1 }, /* keypad 9 */ + { 0x5d, -1, -1, -1 }, + { 0x5e, -1, -1, -1 }, + { 0x5f, -1, -1, -1 }, + + { 0x60, 0x8005, 0x1060, -1 }, /* F5 */ + { 0x61, 0x8006, 0x1061, -1 }, /* F6 */ + { 0x62, 0x8007, 0x1062, -1 }, /* F7 */ + { 0x63, 0x8003, 0x1063, -1 }, /* F3 */ + { 0x64, 0x8008, 0x1064, -1 }, /* F8 */ + { 0x65, 0x8009, 0x1065, -1 }, /* F9 */ + { 0x66, -1, -1, -1 }, + { 0x67, 0x800b, 0x1067, -1 }, /* F11 */ + + { 0x68, -1, -1, -1 }, + { 0x69, 0x800d, 0x1069, -1 }, /* F13 */ + { 0x6a, -1, -1, -1 }, + { 0x6b, 0x800e, 0x106b, -1 }, /* F14 */ + { 0x6c, -1, -1, -1 }, + { 0x6d, 0x800a, 0x106d, -1 }, /* F10 */ + { 0x6e, -1, -1, -1 }, + { 0x6f, 0x800c, 0x106f, -1 }, /* F12 */ + + { 0x70, -1, -1, -1 }, + { 0x71, 0x800f, 0x1071, -1 }, /* F15 */ + { 0x72, 0x1072, 0x1072, -1 }, /* Help, insert */ + { 0x73, 0x1073, 0x1073, -1 }, /* Home */ + { 0x74, 0x1074, 0x1074, -1 }, /* Page up */ + { 0x75, 0x1075, 0x1075, -1 }, /* keypad delete */ + { 0x76, 0x8004, 0x1076, -1 }, /* F4 */ + { 0x77, 0x1077, 0x1077, -1 }, /* keypad end */ + + { 0x78, 0x8002, 0x1078, -1 }, /* F2 */ + { 0x79, 0x1079, 0x1079, -1 }, /* keypad page down */ + { 0x7a, 0x8001, 0x107a, -1 }, /* F1 */ + { 0x7b, 0x08, 0x08, -1 }, /* left */ /* remapped to 0x3b */ + { 0x7c, 0x15, 0x15, -1 }, /* right */ /* remapped to 0x3c */ + { 0x7d, 0x0a, 0x0a, -1 }, /* down */ /* remapped to 0x3d */ + { 0x7e, 0x0b, 0x0b, -1 }, /* up arrow */ /* remapped to 0x3e */ + { 0x7f, -1, -1, -1 }, /* Reset */ +}; diff --git a/src/classes.nib b/src/classes.nib new file mode 100755 index 0000000..ea58db1 --- /dev/null +++ b/src/classes.nib @@ -0,0 +1,4 @@ +{ +IBClasses = (); +IBVersion = 1; +} diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 0000000..442ed70 --- /dev/null +++ b/src/clock.c @@ -0,0 +1,392 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_clock_c[] = "@(#)$KmKId: clock.c,v 1.29 2003-10-17 15:07:35-04 kentd Exp $"; + +#include "defc.h" +#include +#ifdef _WIN32 +# include +# include +#else +# include +#endif + +extern int Verbose; +extern int g_vbl_count; +extern int g_rom_version; +extern int g_config_kegs_update_needed; + +#define CLK_IDLE 1 +#define CLK_TIME 2 +#define CLK_INTERNAL 3 +#define CLK_BRAM1 4 +#define CLK_BRAM2 5 + +int g_clk_mode = CLK_IDLE; +int g_clk_read = 0; +int g_clk_reg1 = 0; + +word32 c033_data = 0; +word32 c034_val = 0; + +byte g_bram[2][256]; +byte *g_bram_ptr = &(g_bram[0][0]); + +word32 g_clk_cur_time = 0xa0000000; +int g_clk_next_vbl_update = 0; + +double +get_dtime() +{ +#ifndef _WIN32 + struct timeval tp1; + double dsec; + double dusec; +#endif + double dtime; + + /* Routine used to return actual system time as a double */ + /* No routine cares about the absolute value, only deltas--maybe */ + /* take advantage of that in future to increase usec accuracy */ + +#ifdef _WIN32 + dtime = timeGetTime() / 1000.0; +#else + +# ifdef SOLARIS + gettimeofday(&tp1, (void *)0); +# else + gettimeofday(&tp1, (struct timezone *)0); +# endif + + dsec = (double)tp1.tv_sec; + dusec = (double)tp1.tv_usec; + + dtime = dsec + (dusec / (1000.0 * 1000.0)); +#endif + + return dtime; +} + +int +micro_sleep(double dtime) +{ +#ifndef _WIN32 + struct timeval Timer; + int ret; +#endif + + if(dtime <= 0.0) { + return 0; + } + if(dtime >= 1.0) { + halt_printf("micro_sleep called with %f!!\n", dtime); + return -1; + } + +#if 0 + printf("usleep: %f\n", dtime); +#endif + +#ifdef _WIN32 + Sleep(dtime * 1000); +#else + Timer.tv_sec = 0; + Timer.tv_usec = (dtime * 1000000.0); + if( (ret = select(0, 0, 0, 0, &Timer)) < 0) { + fprintf(stderr, "micro_sleep (select) ret: %d, errno: %d\n", + ret, errno); + return -1; + } +#endif + return 0; +} + +void +clk_bram_zero() +{ + int i, j; + + /* zero out all bram */ + for(i = 0; i < 2; i++) { + for(j = 0; j < 256; j++) { + g_bram[i][j] = 0; + } + } + g_bram_ptr = &(g_bram[0][0]); +} + +void +clk_bram_set(int bram_num, int offset, int val) +{ + g_bram[bram_num][offset] = val; +} + +void +clk_setup_bram_version() +{ + if(g_rom_version < 3) { + g_bram_ptr = (&g_bram[0][0]); // ROM 01 + } else { + g_bram_ptr = (&g_bram[1][0]); // ROM 03 + } +} + +void +clk_write_bram(FILE *fconf) +{ + int i, j, k; + + for(i = 0; i < 2; i++) { + fprintf(fconf, "\n"); + for(j = 0; j < 256; j += 16) { + fprintf(fconf, "bram%d[%02x] =", 2*i + 1, j); + for(k = 0; k < 16; k++) { + fprintf(fconf, " %02x", g_bram[i][j+k]); + } + fprintf(fconf, "\n"); + } + } +} + +void +update_cur_time() +{ + struct tm *tm_ptr; + time_t cur_time; + unsigned int secs, secs2; + + cur_time = time(0); + + /* Figure out the timezone (effectively) by diffing two times. */ + /* this is probably not right for a few hours around daylight savings*/ + /* time transition */ + secs2 = mktime(gmtime(&cur_time)); + tm_ptr = localtime(&cur_time); + secs = mktime(tm_ptr); + + secs = (unsigned int)cur_time - (secs2 - secs); + + if(tm_ptr->tm_isdst) { + /* adjust for daylight savings time */ + secs += 3600; + } + + /* add in secs to make date based on Apple Jan 1, 1904 instead of */ + /* Unix's Jan 1, 1970 */ + /* So add in 66 years and 17 leap year days (1904 is a leap year) */ + secs += ((66*365) + 17) * (24*3600); + + g_clk_cur_time = secs; + + clk_printf("Update g_clk_cur_time to %08x\n", g_clk_cur_time); + g_clk_next_vbl_update = g_vbl_count + 5; +} + +/* clock_update called by sim65816 every VBL */ +void +clock_update() +{ + /* Nothing to do */ +} + +void +clock_update_if_needed() +{ + int diff; + + diff = g_clk_next_vbl_update - g_vbl_count; + if(diff < 0 || diff > 60) { + /* Been a while, re-read the clock */ + update_cur_time(); + } +} + +word32 +clock_read_c033() +{ + return c033_data; +} + +word32 +clock_read_c034() +{ + return c034_val; +} + +void +clock_write_c033(word32 val) +{ + c033_data = val; +} + +void +clock_write_c034(word32 val) +{ + c034_val = val & 0x7f; + if((val & 0x80) != 0) { + if((val & 0x20) == 0) { + printf("c034 write not last = 1\n"); + /* set_halt(1); */ + } + do_clock_data(); + } +} + + +void +do_clock_data() +{ + word32 mask; + int read; + int op; + + clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode); + + read = c034_val & 0x40; + switch(g_clk_mode) { + case CLK_IDLE: + g_clk_read = (c033_data >> 7) & 1; + g_clk_reg1 = (c033_data >> 2) & 3; + op = (c033_data >> 4) & 7; + if(!read) { + /* write */ + switch(op) { + case 0x0: /* Read/write seconds register */ + g_clk_mode = CLK_TIME; + clock_update_if_needed(); + break; + case 0x3: /* internal registers */ + g_clk_mode = CLK_INTERNAL; + if(g_clk_reg1 & 0x2) { + /* extend BRAM read */ + g_clk_mode = CLK_BRAM2; + g_clk_reg1 = (c033_data & 7) << 5; + } + break; + case 0x2: /* read/write ram 0x10-0x13 */ + g_clk_mode = CLK_BRAM1; + g_clk_reg1 += 0x10; + break; + case 0x4: /* read/write ram 0x00-0x0f */ + case 0x5: case 0x6: case 0x7: + g_clk_mode = CLK_BRAM1; + g_clk_reg1 = (c033_data >> 2) & 0xf; + break; + default: + halt_printf("Bad c033_data in CLK_IDLE: %02x\n", + c033_data); + } + } else { + printf("clk read from IDLE mode!\n"); + /* set_halt(1); */ + g_clk_mode = CLK_IDLE; + } + break; + case CLK_BRAM2: + if(!read) { + /* get more bits of bram addr */ + if((c033_data & 0x83) == 0x00) { + /* more address bits */ + g_clk_reg1 |= ((c033_data >> 2) & 0x1f); + g_clk_mode = CLK_BRAM1; + } else { + halt_printf("CLK_BRAM2: c033_data: %02x!\n", + c033_data); + g_clk_mode = CLK_IDLE; + } + } else { + halt_printf("CLK_BRAM2: clock read!\n"); + g_clk_mode = CLK_IDLE; + } + break; + case CLK_BRAM1: + /* access battery ram addr g_clk_reg1 */ + if(read) { + if(g_clk_read) { + /* Yup, read */ + c033_data = g_bram_ptr[g_clk_reg1]; + clk_printf("Reading BRAM loc %02x: %02x\n", + g_clk_reg1, c033_data); + } else { + halt_printf("CLK_BRAM1: said wr, now read\n"); + } + } else { + if(g_clk_read) { + halt_printf("CLK_BRAM1: said rd, now write\n"); + } else { + /* Yup, write */ + clk_printf("Writing BRAM loc %02x with %02x\n", + g_clk_reg1, c033_data); + g_bram_ptr[g_clk_reg1] = c033_data; + g_config_kegs_update_needed = 1; + } + } + g_clk_mode = CLK_IDLE; + break; + case CLK_TIME: + if(read) { + if(g_clk_read == 0) { + halt_printf("Reading time, but in set mode!\n"); + } + c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) & 0xff; + clk_printf("Returning time byte %d: %02x\n", + g_clk_reg1, c033_data); + } else { + /* Write */ + if(g_clk_read) { + halt_printf("Write time, but in read mode!\n"); + } + clk_printf("Writing TIME loc %d with %02x\n", + g_clk_reg1, c033_data); + mask = 0xff << (8 * g_clk_reg1); + + g_clk_cur_time = (g_clk_cur_time & (~mask)) | + ((c033_data & 0xff) << (8 *g_clk_reg1)); + } + g_clk_mode = CLK_IDLE; + break; + case CLK_INTERNAL: + if(read) { + printf("Attempting to read internal reg %02x!\n", + g_clk_reg1); + } else { + switch(g_clk_reg1) { + case 0x0: /* test register */ + if(c033_data & 0xc0) { + printf("Writing test reg: %02x!\n", + c033_data); + /* set_halt(1); */ + } + break; + case 0x1: /* write protect reg */ + clk_printf("Writing clk wr_protect: %02x\n", + c033_data); + if(c033_data & 0x80) { + printf("Stop, wr clk wr_prot: %02x\n", + c033_data); + /* set_halt(1); */ + } + break; + default: + halt_printf("Writing int reg: %02x with %02x\n", + g_clk_reg1, c033_data); + } + } + g_clk_mode = CLK_IDLE; + break; + default: + halt_printf("clk mode: %d unknown!\n", g_clk_mode); + g_clk_mode = CLK_IDLE; + break; + } +} + diff --git a/src/compile_time.c b/src/compile_time.c new file mode 100644 index 0000000..e937797 --- /dev/null +++ b/src/compile_time.c @@ -0,0 +1,5 @@ + +const char rcsid_compile_time_c[] = "@(#)$KmKId: compile_time.c,v 1.2 2002-11-14 01:02:44-05 kadickey Exp $"; + +char g_compile_time[] = "Compiled: " __DATE__ " " __TIME__ ; + diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..b9987b1 --- /dev/null +++ b/src/config.c @@ -0,0 +1,2560 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2003 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_config_c[] = "@(#)$KmKId: config.c,v 1.30 2003-11-21 16:38:53-05 kentd Exp $"; + +#include "defc.h" +#include +#include "config.h" +#include + +extern int Verbose; +extern word32 g_vbl_count; +extern Iwm iwm; + +extern int g_track_bytes_35[]; +extern int g_track_nibs_35[]; +extern int g_apple35_sel; + +extern int g_cur_a2_stat; +extern byte *g_slow_memory_ptr; +extern double g_cur_dcycs; + +extern word32 g_adb_repeat_vbl; + +extern int g_limit_speed; +extern int g_force_depth; +extern int g_raw_serial; +extern int g_serial_out_masking; +extern word32 g_mem_size_exp; +extern int g_video_line_update_interval; + +extern int g_screen_index[]; +extern word32 g_full_refresh_needed; +extern word32 g_a2_screen_buffer_changed; +extern int g_a2_new_all_stat[]; +extern int g_new_a2_stat_cur_line; + +extern int g_key_down; +extern const char g_kegs_version_str[]; + +int g_config_control_panel = 0; +char g_config_kegs_name[256]; +char g_cfg_cwd_str[CFG_PATH_MAX] = { 0 }; + +int g_config_kegs_auto_update = 1; +int g_config_kegs_update_needed = 0; + +const char *g_config_kegs_name_list[] = { + "config.kegs", "kegs_conf", ".config.kegs", 0 +}; + +int g_highest_smartport_unit = -1; +int g_reparse_delay = 0; + +byte g_save_text_screen_bytes[0x800]; +word32 g_save_cur_a2_stat = 0; +char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; +char g_config_kegs_buf[CONF_BUF_LEN]; + +word32 g_cfg_vbl_count = 0; + +int g_cfg_curs_x = 0; +int g_cfg_curs_y = 0; +int g_cfg_curs_inv = 0; +int g_cfg_curs_mousetext = 0; + +#define CFG_MAX_OPTS 16 +#define CFG_OPT_MAXSTR 100 + +int g_cfg_opts_vals[CFG_MAX_OPTS]; +char g_cfg_opts_strs[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; +char g_cfg_opt_buf[CFG_OPT_MAXSTR]; + +#define MAX_PARTITION_BLK_SIZE 65536 + +extern Cfg_menu g_cfg_main_menu[]; + +#define KNMP(a) &a, #a, 0 + +Cfg_menu g_cfg_disk_menu[] = { +{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, +{ "s5d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x5000 }, +{ "s5d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x5010 }, +{ "", 0, 0, 0, 0 }, +{ "s6d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x6000 }, +{ "s6d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x6010 }, +{ "", 0, 0, 0, 0 }, +{ "s7d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x7000 }, +{ "s7d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x7010 }, +{ "s7d3 = ", 0, 0, 0, CFGTYPE_DISK + 0x7020 }, +{ "s7d4 = ", 0, 0, 0, CFGTYPE_DISK + 0x7030 }, +{ "s7d5 = ", 0, 0, 0, CFGTYPE_DISK + 0x7040 }, +{ "s7d6 = ", 0, 0, 0, CFGTYPE_DISK + 0x7050 }, +{ "s7d7 = ", 0, 0, 0, CFGTYPE_DISK + 0x7060 }, +{ "s7d8 = ", 0, 0, 0, CFGTYPE_DISK + 0x7070 }, +{ "s7d9 = ", 0, 0, 0, CFGTYPE_DISK + 0x7080 }, +{ "s7d10 = ", 0, 0, 0, CFGTYPE_DISK + 0x7090 }, +{ "s7d11 = ", 0, 0, 0, CFGTYPE_DISK + 0x70a0 }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_main_menu[] = { +{ "KEGS Configuration", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, +{ "Force X-windows display depth", KNMP(g_force_depth), CFGTYPE_INT }, +{ "Auto-update config.kegs,0,Manual,1,Immediately", + KNMP(g_config_kegs_auto_update), CFGTYPE_INT }, +{ "Speed,0,Unlimited,1,1.0MHz,2,2.8MHz,3,8.0MHz (Zip)", + KNMP(g_limit_speed), CFGTYPE_INT }, +{ "Expansion Mem Size,0,0MB,0x100000,1MB,0x200000,2MB,0x300000,3MB," + "0x400000,4MB,0x600000,6MB,0x800000,8MB,0xa00000,10MB,0xc00000,12MB," + "0xe00000,14MB", KNMP(g_mem_size_exp), CFGTYPE_INT }, +{ "Serial Ports,0,Only use sockets 6501-6502,1,Use real ports if avail", + KNMP(g_raw_serial), CFGTYPE_INT }, +{ "Serial Output,0,Send full 8-bit data,1,Mask off high bit", + KNMP(g_serial_out_masking), CFGTYPE_INT }, +{ "3200 Color Enable,0,Auto (Full if fast enough),1,Full (Update every line)," + "8,Off (Update video every 8 lines)", + KNMP(g_video_line_update_interval), CFGTYPE_INT }, +{ "Dump text screen to file", (void *)cfg_text_screen_dump, 0, 0, CFGTYPE_FUNC}, +{ "", 0, 0, 0, 0 }, +{ "Save changes to config.kegs", (void *)config_write_config_kegs_file, 0, 0, + CFGTYPE_FUNC }, +{ "", 0, 0, 0, 0 }, +{ "Exit Config (or press F4)", (void *)cfg_exit, 0, 0, CFGTYPE_FUNC }, +{ 0, 0, 0, 0, 0 }, +}; + + +#define CFG_MAX_DEFVALS 128 +Cfg_defval g_cfg_defvals[CFG_MAX_DEFVALS]; +int g_cfg_defval_index = 0; + +int g_cfg_slotdrive = -1; +int g_cfg_select_partition = -1; +char g_cfg_tmp_path[CFG_PATH_MAX]; +char g_cfg_file_path[CFG_PATH_MAX]; +char g_cfg_file_cachedpath[CFG_PATH_MAX]; +char g_cfg_file_cachedreal[CFG_PATH_MAX]; +char g_cfg_file_curpath[CFG_PATH_MAX]; +char g_cfg_file_shortened[CFG_PATH_MAX]; +char g_cfg_file_match[CFG_PATH_MAX]; + +Cfg_listhdr g_cfg_dirlist = { 0 }; +Cfg_listhdr g_cfg_partitionlist = { 0 }; + +int g_cfg_file_pathfield = 0; + +void +config_init_menus(Cfg_menu *menuptr) +{ + void *voidptr; + const char *name_str; + Cfg_defval *defptr; + int type; + int pos; + int val; + + if(menuptr[0].defptr != 0) { + return; + } + menuptr[0].defptr = (void *)1; + pos = 0; + while(pos < 100) { + type = menuptr->cfgtype; + voidptr = menuptr->ptr; + name_str = menuptr->name_str; + if(menuptr->str == 0) { + break; + } + if(name_str != 0) { + defptr = &(g_cfg_defvals[g_cfg_defval_index++]); + if(g_cfg_defval_index >= CFG_MAX_DEFVALS) { + printf("CFG_MAX_DEFVAL overflow\n"); + my_exit(5); + } + defptr->menuptr = menuptr; + defptr->intval = 0; + switch(type) { + case CFGTYPE_INT: + val = *((int *)voidptr); + defptr->intval = val; + menuptr->defptr = &(defptr->intval); + break; + default: + printf("name_str is %p = %s, but type: %d\n", + name_str, name_str, type); + my_exit(5); + } + } + if(type == CFGTYPE_MENU) { + config_init_menus((Cfg_menu *)voidptr); + } + pos++; + menuptr++; + } +} + +void +config_init() +{ + config_init_menus(g_cfg_main_menu); + + // Find the config.kegs file + setup_kegs_file(&g_config_kegs_name[0], sizeof(g_config_kegs_name), 0, + &g_config_kegs_name_list[0]); + + config_parse_config_kegs_file(); +} + +void +cfg_exit() +{ + /* printf("In cfg exit\n"); */ + g_config_control_panel = 0; +} + +void +cfg_text_screen_dump() +{ + char buf[85]; + char *filename; + FILE *ofile; + int offset; + int c; + int pos; + int i, j; + + filename = "kegs.screen.dump"; + printf("Writing text screen to the file %s\n", filename); + ofile = fopen(filename, "w"); + if(ofile == 0) { + printf("fopen ret 0, errno: %d\n", errno); + return; + } + + for(i = 0; i < 24; i++) { + pos = 0; + for(j = 0; j < 40; j++) { + offset = g_screen_index[i] + j; + if(g_save_cur_a2_stat & ALL_STAT_VID80) { + c = g_save_text_screen_bytes[0x400+offset]; + c = c & 0x7f; + if(c < 0x20) { + c += 0x40; + } + buf[pos++] = c; + } + c = g_save_text_screen_bytes[offset] & 0x7f; + if(c < 0x20) { + c += 0x40; + } + buf[pos++] = c; + } + while((pos > 0) && (buf[pos-1] == ' ')) { + /* try to strip out trailing spaces */ + pos--; + } + buf[pos++] = '\n'; + buf[pos++] = 0; + fputs(buf, ofile); + } + fclose(ofile); +} + +void +config_vbl_update(int doit_3_persec) +{ + if(doit_3_persec) { + if(g_config_kegs_auto_update && g_config_kegs_update_needed) { + config_write_config_kegs_file(); + } + } + return; +} + +void +config_parse_option(char *buf, int pos, int len, int line) +{ + Cfg_menu *menuptr; + Cfg_defval *defptr; + char *nameptr; + int *iptr; + int num_equals; + int type; + int val; + int c; + int i; + +// warning: modifies buf (turns spaces to nulls) +// parse buf from pos into option, "=" and then "rest" + if(pos >= len) { + /* blank line */ + return; + } + + if(strncmp(&buf[pos], "bram", 4) == 0) { + config_parse_bram(buf, pos+4, len); + return; + } + + // find "name" as first contiguous string + printf("...parse_option: line %d, %p,%p = %s (%s) len:%d\n", line, + &buf[pos], buf, &buf[pos], buf, len); + + nameptr = &buf[pos]; + while(pos < len) { + c = buf[pos]; + if(c == 0 || c == ' ' || c == '\t' || c == '\n') { + break; + } + pos++; + } + buf[pos] = 0; + pos++; + + // Eat up all whitespace and '=' + num_equals = 0; + while(pos < len) { + c = buf[pos]; + if((c == '=') && num_equals == 0) { + pos++; + num_equals++; + } else if(c == ' ' || c == '\t') { + pos++; + } else { + break; + } + } + + /* Look up nameptr to find type */ + type = -1; + defptr = 0; + menuptr = 0; + for(i = 0; i < g_cfg_defval_index; i++) { + defptr = &(g_cfg_defvals[i]); + menuptr = defptr->menuptr; + if(strcmp(menuptr->name_str, nameptr) == 0) { + type = menuptr->cfgtype; + break; + } + } + + switch(type) { + case CFGTYPE_INT: + /* use strtol */ + val = (int)strtol(&buf[pos], 0, 0); + iptr = (int *)menuptr->ptr; + *iptr = val; + break; + default: + printf("Config file variable %s is unknown type: %d\n", + nameptr, type); + } + +} + +void +config_parse_bram(char *buf, int pos, int len) +{ + int bram_num; + int offset; + int val; + + if((len < (pos+5)) || (buf[pos+1] != '[') || (buf[pos+4] != ']')) { + printf("Malformed bram statement: %s\n", buf); + return; + } + bram_num = buf[pos] - '0'; + if(bram_num != 1 && bram_num != 3) { + printf("Malformed bram number: %s\n", buf); + return; + } + + bram_num = bram_num >> 1; // turn 3->1 and 1->0 + + offset = strtoul(&(buf[pos+2]), 0, 16); + pos += 5; + while(pos < len) { + while(buf[pos] == ' ' || buf[pos] == '\t' || buf[pos] == 0x0a || + buf[pos] == 0x0d || buf[pos] == '=') { + pos++; + } + val = strtoul(&buf[pos], 0, 16); + clk_bram_set(bram_num, offset, val); + offset++; + pos += 2; + } +} + +void +config_parse_config_kegs_file() +{ + FILE *fconf; + char *buf; + char *ptr; + char *name_ptr; + char *partition_name; + int part_num; + int ejected; + int line; + int pos; + int slot; + int drive; + int size; + int len; + int ret; + int i; + + printf("Parsing config.kegs file\n"); + + clk_bram_zero(); + + g_highest_smartport_unit = -1; + + cfg_get_base_path(&g_cfg_cwd_str[0], g_config_kegs_name, 0); + if(g_cfg_cwd_str[0] != 0) { + ret = chdir(&g_cfg_cwd_str[0]); + if(ret != 0) { + printf("chdir to %s, errno:%d\n", g_cfg_cwd_str, errno); + } + } + + /* In any case, copy the directory path to g_cfg_cwd_str */ + (void)getcwd(&g_cfg_cwd_str[0], CFG_PATH_MAX); + + fconf = fopen(g_config_kegs_name, "rt"); + if(fconf == 0) { + printf("cannot open disk_conf! Stopping!\n"); + exit(3); + } + + line = 0; + while(1) { + buf = &g_config_kegs_buf[0]; + ptr = fgets(buf, CONF_BUF_LEN, fconf); + if(ptr == 0) { + iwm_printf("Done reading disk_conf\n"); + break; + } + + line++; + /* strip off newline(s) */ + len = strlen(buf); + for(i = len - 1; i >= 0; i--) { + if((buf[i] != 0x0d) && (buf[i] != 0x0a)) { + break; + } + len = i; + buf[i] = 0; + } + + iwm_printf("disk_conf[%d]: %s\n", line, buf); + if(len > 0 && buf[0] == '#') { + iwm_printf("Skipping comment\n"); + continue; + } + + /* determine what this is */ + pos = 0; + + while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t') ) { + pos++; + } + if((pos + 4) > len || buf[pos] != 's' || buf[pos+2] != 'd' || + buf[pos+1] > '9' || buf[pos+1] < '0') { + config_parse_option(buf, pos, len, line); + continue; + } + + slot = buf[pos+1] - '0'; + drive = buf[pos+3] - '0'; + + /* skip over slot, drive */ + pos += 4; + if(buf[pos] >= '0' && buf[pos] <= '9') { + drive = drive * 10 + buf[pos] - '0'; + pos++; + } + + /* make s6d1 mean index 0 */ + drive--; + + while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t' || + buf[pos] == '=') ) { + pos++; + } + + ejected = 0; + if(buf[pos] == '#') { + /* disk is ejected, but read all the info anyway */ + ejected = 1; + pos++; + } + + size = 0; + if(buf[pos] == ',') { + /* read optional size parameter */ + pos++; + while(pos < len && buf[pos] >= '0' && buf[pos] <= '9'){ + size = size * 10 + buf[pos] - '0'; + pos++; + } + size = size * 1024; + if(buf[pos] == ',') { + pos++; /* eat trailing ',' */ + } + } + + /* see if it has a partition name */ + partition_name = 0; + part_num = -1; + if(buf[pos] == ':') { + pos++; + /* yup, it's got a partition name! */ + partition_name = &buf[pos]; + while((pos < len) && (buf[pos] != ':')) { + pos++; + } + buf[pos] = 0; /* null terminate partition name */ + pos++; + } + if(buf[pos] == ';') { + pos++; + /* it's got a partition number */ + part_num = 0; + while((pos < len) && (buf[pos] != ':')) { + part_num = (10*part_num) + buf[pos] - '0'; + pos++; + } + pos++; + } + + /* Get filename */ + name_ptr = &(buf[pos]); + if(name_ptr[0] == 0) { + continue; + } + + insert_disk(slot, drive, name_ptr, ejected, size, + partition_name, part_num); + + } + + ret = fclose(fconf); + if(ret != 0) { + printf("Closing disk_conf ret: %d, errno: %d\n", ret, errno); + exit(4); + } + + iwm_printf("Done parsing disk_conf file\n"); +} + + +Disk * +cfg_get_dsk_from_slot_drive(int slot, int drive) +{ + Disk *dsk; + int max_drive; + + /* Get dsk */ + max_drive = 2; + switch(slot) { + case 5: + dsk = &(iwm.drive35[drive]); + break; + case 6: + dsk = &(iwm.drive525[drive]); + break; + default: + max_drive = MAX_C7_DISKS; + dsk = &(iwm.smartport[drive]); + } + + if(drive >= max_drive) { + dsk -= drive; /* move back to drive 0 effectively */ + } + + return dsk; +} + +void +config_generate_config_kegs_name(char *outstr, int maxlen, Disk *dsk, + int with_extras) +{ + char *str; + + str = outstr; + + if(with_extras && dsk->fd < 0) { + snprintf(str, maxlen - (str - outstr), "#"); + str = &outstr[strlen(outstr)]; + } + if(with_extras && dsk->force_size > 0) { + snprintf(str, maxlen - (str - outstr), ",%d,", dsk->force_size); + str = &outstr[strlen(outstr)]; + } + if(with_extras && dsk->partition_name != 0) { + snprintf(str, maxlen - (str - outstr), ":%s:", + dsk->partition_name); + str = &outstr[strlen(outstr)]; + } else if(with_extras && dsk->partition_num >= 0) { + snprintf(str, maxlen - (str - outstr), ";%d:", + dsk->partition_num); + str = &outstr[strlen(outstr)]; + } + snprintf(str, maxlen - (str - outstr), "%s", dsk->name_ptr); +} + +void +config_write_config_kegs_file() +{ + FILE *fconf; + Disk *dsk; + Cfg_defval *defptr; + Cfg_menu *menuptr; + int defval, curval; + int type; + int slot, drive; + int i; + + printf("Writing config.kegs file to %s\n", g_config_kegs_name); + + fconf = fopen(g_config_kegs_name, "w+"); + if(fconf == 0) { + halt_printf("cannot open %s! Stopping!\n"); + return; + } + + fprintf(fconf, "# KEGS configuration file version %s\n", + g_kegs_version_str); + + for(i = 0; i < MAX_C7_DISKS + 4; i++) { + slot = 7; + drive = i - 4; + if(i < 4) { + slot = (i >> 1) + 5; + drive = i & 1; + } + if(drive == 0) { + fprintf(fconf, "\n"); /* an extra blank line */ + } + + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + if(dsk->name_ptr == 0 && (i > 4)) { + /* No disk, not even ejected--just skip */ + continue; + } + fprintf(fconf, "s%dd%d = ", slot, drive + 1); + if(dsk->name_ptr == 0) { + fprintf(fconf, "\n"); + continue; + } + config_generate_config_kegs_name(&g_cfg_tmp_path[0], + CFG_PATH_MAX, dsk, 1); + fprintf(fconf, "%s\n", &g_cfg_tmp_path[0]); + } + + fprintf(fconf, "\n"); + + /* See if any variables are different than their default */ + for(i = 0; i < g_cfg_defval_index; i++) { + defptr = &(g_cfg_defvals[i]); + menuptr = defptr->menuptr; + defval = defptr->intval; + type = menuptr->cfgtype; + if(type != CFGTYPE_INT) { + /* skip it */ + continue; + } + curval = *((int *)menuptr->ptr); + if(curval != defval) { + fprintf(fconf, "%s = %d\n", menuptr->name_str, curval); + } + } + + fprintf(fconf, "\n"); + + /* write bram state */ + clk_write_bram(fconf); + + fclose(fconf); + + g_config_kegs_update_needed = 0; +} + +void +insert_disk(int slot, int drive, const char *name, int ejected, int force_size, + const char *partition_name, int part_num) +{ + byte buf_2img[512]; + Disk *dsk; + char *name_ptr, *uncomp_ptr, *system_str; + char *part_ptr; + int size; + int system_len; + int part_len; + int cmp_o, cmp_p, cmp_dot; + int cmp_b, cmp_i, cmp_n; + int can_write; + int len; + int nibs; + int unix_pos; + int name_len; + int image_identified; + int exp_size; + int save_track; + int ret; + int tmp; + int i; + + g_config_kegs_update_needed = 1; + + if((slot < 5) || (slot > 7)) { + printf("insert_disk: Invalid slot: %d\n", slot); + return; + } + if(drive < 0 || ((slot == 7) && (drive >= MAX_C7_DISKS)) || + ((slot < 7) && (drive > 1))) { + printf("insert_disk: Invalid drive: %d\n", drive); + return; + } + + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + +#if 0 + printf("Inserting disk %s (%s or %d) in slot %d, drive: %d\n", name, + partition_name, part_num, slot, drive); +#endif + + dsk->just_ejected = 0; + dsk->force_size = force_size; + + if(dsk->fd >= 0) { + eject_disk(dsk); + } + + /* Before opening, make sure no other mounted disk has this name */ + /* If so, unmount it */ + if(!ejected) { + for(i = 0; i < 2; i++) { + eject_named_disk(&iwm.drive525[i], name,partition_name); + eject_named_disk(&iwm.drive35[i], name, partition_name); + } + for(i = 0; i < MAX_C7_DISKS; i++) { + eject_named_disk(&iwm.smartport[i],name,partition_name); + } + } + + if(dsk->name_ptr != 0) { + /* free old name_ptr */ + free(dsk->name_ptr); + } + + name_len = strlen(name) + 1; + name_ptr = (char *)malloc(name_len); + strncpy(name_ptr, name, name_len); + dsk->name_ptr = name_ptr; + + dsk->partition_name = 0; + if(partition_name != 0) { + part_len = strlen(partition_name) + 1; + part_ptr = (char *)malloc(part_len); + strncpy(part_ptr, partition_name, part_len); + dsk->partition_name = part_ptr; + } + dsk->partition_num = part_num; + + iwm_printf("Opening up disk image named: %s\n", name_ptr); + + if(ejected) { + /* just get out of here */ + dsk->fd = -1; + return; + } + + dsk->fd = -1; + can_write = 1; + + if((name_len > 4) && (strcmp(&name_ptr[name_len - 4], ".gz") == 0)) { + + /* it's gzip'ed, try to gunzip it, then unlink the */ + /* uncompressed file */ + + can_write = 0; + + uncomp_ptr = (char *)malloc(name_len); + strncpy(uncomp_ptr, name_ptr, name_len); + uncomp_ptr[name_len - 4] = 0; + + system_len = name_len + 200; + system_str = (char *)malloc(system_len + 1); + snprintf(system_str, system_len, + "set -o noclobber;gunzip -c %s > %s", name_ptr, + uncomp_ptr); + printf("I am uncompressing %s into %s for mounting\n", + name_ptr, uncomp_ptr); + ret = system(system_str); + if(ret == 0) { + /* successfully ran */ + dsk->fd = open(uncomp_ptr, O_RDONLY | O_BINARY, 0x1b6); + iwm_printf("Opening .gz file %s is fd: %d\n", + uncomp_ptr, dsk->fd); + + /* and, unlink the temporary file */ + (void)unlink(uncomp_ptr); + } + free(system_str); + free(uncomp_ptr); + } + + if(dsk->fd < 0 && can_write) { + dsk->fd = open(name_ptr, O_RDWR | O_BINARY, 0x1b6); + } + + if(dsk->fd < 0 && can_write) { + printf("Trying to open %s read-only, errno: %d\n", name_ptr, + errno); + dsk->fd = open(name_ptr, O_RDONLY | O_BINARY, 0x1b6); + can_write = 0; + } + + iwm_printf("open returned: %d\n", dsk->fd); + + if(dsk->fd < 0) { + printf("Disk image %s does not exist!\n", name_ptr); + return; + } + + if(can_write != 0) { + dsk->write_prot = 0; + dsk->write_through_to_unix = 1; + } else { + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + + save_track = dsk->cur_qtr_track; /* save arm position */ + dsk->image_type = DSK_TYPE_PRODOS; + + /* See if it is in 2IMG format */ + ret = read(dsk->fd, (char *)&buf_2img[0], 512); + size = force_size; + if(size <= 0) { + size = cfg_get_fd_size(dsk->fd); + } + image_identified = 0; + if(buf_2img[0] == '2' && buf_2img[1] == 'I' && buf_2img[2] == 'M' && + buf_2img[3] == 'G') { + /* It's a 2IMG disk */ + printf("Image named %s is in 2IMG format\n", dsk->name_ptr); + image_identified = 1; + + if(buf_2img[12] == 0) { + printf("2IMG is in DOS 3.3 sector order\n"); + dsk->image_type = DSK_TYPE_DOS33; + } + if(buf_2img[19] & 0x80) { + /* disk is locked */ + printf("2IMG is write protected\n"); + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + if((buf_2img[17] & 1) && (dsk->image_type == DSK_TYPE_DOS33)) { + dsk->vol_num = buf_2img[16]; + printf("Setting DOS 3.3 vol num to %d\n", dsk->vol_num); + } + // Some 2IMG archives have the size byte reversed + size = (buf_2img[31] << 24) + (buf_2img[30] << 16) + + (buf_2img[29] << 8) + buf_2img[28]; + unix_pos = (buf_2img[27] << 24) + (buf_2img[26] << 16) + + (buf_2img[25] << 8) + buf_2img[24]; + if(size == 0x800c00) { + // Byte reversed 0x0c8000 + size = 0x0c8000; + } + if(size == 0) { + /* From KEGS-OS-X: Gilles Tschopp: */ + /* deal with corrupted 2IMG files */ + printf("Bernie corrupted size to 0...working around\n"); + + /* Just get the full size, and subtract 64, and */ + /* then round down to lower 0x1000 boundary */ + size = cfg_get_fd_size(dsk->fd) - 64; + size = size & -0x1000; + } + dsk->image_start = unix_pos; + dsk->image_size = size; + } + exp_size = 800*1024; + if(dsk->disk_525) { + exp_size = 140*1024; + } + if(!image_identified) { + /* See if it might be the Mac diskcopy format */ + tmp = (buf_2img[0x40] << 24) + (buf_2img[0x41] << 16) + + (buf_2img[0x42] << 8) + buf_2img[0x43]; + if((size >= (exp_size + 0x54)) && (tmp == exp_size)) { + /* It's diskcopy since data size field matches */ + printf("Image named %s is in Mac diskcopy format\n", + dsk->name_ptr); + image_identified = 1; + dsk->image_start = 0x54; + dsk->image_size = exp_size; + dsk->image_type = DSK_TYPE_PRODOS; /* ProDOS */ + } + } + if(!image_identified) { + /* Assume raw image */ + dsk->image_start = 0; + dsk->image_size = size; + dsk->image_type = DSK_TYPE_PRODOS; + if(dsk->disk_525) { + dsk->image_type = DSK_TYPE_DOS33; + if(name_len >= 5) { + cmp_o = dsk->name_ptr[name_len-2]; + cmp_p = dsk->name_ptr[name_len-3]; + cmp_dot = dsk->name_ptr[name_len-4]; + if(cmp_dot == '.' && + (cmp_p == 'p' || cmp_p == 'P') && + (cmp_o == 'o' || cmp_o == 'O')) { + dsk->image_type = DSK_TYPE_PRODOS; + } + + cmp_b = dsk->name_ptr[name_len-2]; + cmp_i = dsk->name_ptr[name_len-3]; + cmp_n = dsk->name_ptr[name_len-4]; + cmp_dot = dsk->name_ptr[name_len-5]; + if(cmp_dot == '.' && + (cmp_n == 'n' || cmp_n == 'N') && + (cmp_i == 'i' || cmp_i == 'I') && + (cmp_b == 'b' || cmp_b == 'B')) { + dsk->image_type = DSK_TYPE_NIB; + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + } + } + } + + dsk->disk_dirty = 0; + dsk->nib_pos = 0; + + if(dsk->smartport) { + g_highest_smartport_unit = MAX(dsk->drive, + g_highest_smartport_unit); + + if(partition_name != 0 || part_num >= 0) { + ret = cfg_partition_find_by_name_or_num(dsk->fd, + partition_name, part_num, dsk); + printf("partition %s (num %d) mounted, wr_prot: %d\n", + partition_name, part_num, dsk->write_prot); + + if(ret < 0) { + close(dsk->fd); + dsk->fd = -1; + return; + } + } + iwm_printf("adding smartport device[%d], size:%08x, " + "img_sz:%08x\n", dsk->drive, dsk->tracks[0].unix_len, + dsk->image_size); + } else if(dsk->disk_525) { + unix_pos = dsk->image_start; + size = dsk->image_size; + dsk->num_tracks = 4*35; + len = 0x1000; + nibs = NIB_LEN_525; + if(dsk->image_type == DSK_TYPE_NIB) { + len = dsk->image_size / 35;; + nibs = len; + } + if(size != 35*len) { + printf("Disk 5.25 error: size is %d, not %d\n",size, + 35*len); + } + for(i = 0; i < 35; i++) { + iwm_move_to_track(dsk, 4*i); + disk_unix_to_nib(dsk, 4*i, unix_pos, len, nibs); + unix_pos += len; + } + } else { + /* disk_35 */ + unix_pos = dsk->image_start; + size = dsk->image_size; + if(size != 800*1024) { + printf("Disk 3.5 error: size is %d, not 800K\n", size); + } + dsk->num_tracks = 2*80; + for(i = 0; i < 2*80; i++) { + iwm_move_to_track(dsk, i); + len = g_track_bytes_35[i >> 5]; + nibs = g_track_nibs_35[i >> 5]; + iwm_printf("Trk: %d.%d = unix: %08x, %04x, %04x\n", + i>>1, i & 1, unix_pos, len, nibs); + disk_unix_to_nib(dsk, i, unix_pos, len, nibs); + unix_pos += len; + + iwm_printf(" trk_len:%05x\n",dsk->tracks[i].track_len); + } + } + + iwm_move_to_track(dsk, save_track); + +} + +void +eject_named_disk(Disk *dsk, const char *name, const char *partition_name) +{ + + if(dsk->fd < 0) { + return; + } + + /* If name matches, eject the disk! */ + if(!strcmp(dsk->name_ptr, name)) { + /* It matches, eject it */ + if((partition_name != 0) && (dsk->partition_name != 0)) { + /* If both have partitions, and they differ, then */ + /* don't eject. Otherwise, eject */ + if(strcmp(dsk->partition_name, partition_name) != 0) { + /* Don't eject */ + return; + } + } + eject_disk(dsk); + } +} + +void +eject_disk_by_num(int slot, int drive) +{ + Disk *dsk; + + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + + eject_disk(dsk); +} + +void +eject_disk(Disk *dsk) +{ + int motor_on; + int i; + + if(dsk->fd < 0) { + return; + } + + g_config_kegs_update_needed = 1; + + motor_on = iwm.motor_on; + if(g_apple35_sel) { + motor_on = iwm.motor_on35; + } + if(motor_on) { + halt_printf("Try eject dsk:%s, but motor_on!\n", dsk->name_ptr); + } + + iwm_flush_disk_to_unix(dsk); + + printf("Ejecting disk: %s\n", dsk->name_ptr); + + /* Free all memory, close file */ + + /* free the tracks first */ + for(i = 0; i < dsk->num_tracks; i++) { + if(dsk->tracks[i].nib_area) { + free(dsk->tracks[i].nib_area); + } + dsk->tracks[i].nib_area = 0; + dsk->tracks[i].track_len = 0; + } + dsk->num_tracks = 0; + + /* close file, clean up dsk struct */ + close(dsk->fd); + + dsk->image_start = 0; + dsk->image_size = 0; + dsk->nib_pos = 0; + dsk->disk_dirty = 0; + dsk->write_through_to_unix = 0; + dsk->write_prot = 1; + dsk->fd = -1; + dsk->just_ejected = 1; + + /* Leave name_ptr valid */ +} + +int +cfg_get_fd_size(int fd) +{ + struct stat stat_buf; + int ret; + + ret = fstat(fd, &stat_buf); + if(ret != 0) { + fprintf(stderr,"fstat returned %d on fd %d, errno: %d\n", + ret, fd, errno); + stat_buf.st_size = 0; + } + + return stat_buf.st_size; +} + +int +cfg_partition_read_block(int fd, void *buf, int blk, int blk_size) +{ + int ret; + + ret = lseek(fd, blk * blk_size, SEEK_SET); + if(ret != blk * blk_size) { + printf("lseek: %08x, wanted: %08x, errno: %d\n", ret, + blk * blk_size, errno); + return 0; + } + + ret = read(fd, (char *)buf, blk_size); + if(ret != blk_size) { + printf("ret: %08x, wanted %08x, errno: %d\n", ret, blk_size, + errno); + return 0; + } + return ret; +} + +int +cfg_partition_find_by_name_or_num(int fd, const char *partnamestr, int part_num, + Disk *dsk) +{ + Cfg_dirent *direntptr; + int match; + int num_parts; + int i; + + num_parts = cfg_partition_make_list(fd); + + if(num_parts <= 0) { + return -1; + } + + for(i = 0; i < g_cfg_partitionlist.last; i++) { + direntptr = &(g_cfg_partitionlist.direntptr[i]); + match = 0; + if((strncmp(partnamestr, direntptr->name, 32) == 0) && + (part_num < 0)) { + //printf("partition, match1, name:%s %s, part_num:%d\n", + // partnamestr, direntptr->name, part_num); + + match = 1; + } + if((partnamestr == 0) && (direntptr->part_num == part_num)) { + //printf("partition, match2, n:%s, part_num:%d == %d\n", + // direntptr->name, direntptr->part_num, part_num); + match = 1; + } + if(match) { + dsk->image_start = direntptr->image_start; + dsk->image_size = direntptr->size; + //printf("match with image_start: %08x, image_size: " + // "%08x\n", dsk->image_start, dsk->image_size); + + return i; + } + } + + return -1; +} + +int +cfg_partition_make_list(int fd) +{ + Driver_desc *driver_desc_ptr; + Part_map *part_map_ptr; + word32 *blk_bufptr; + word32 start; + word32 len; + word32 data_off; + word32 data_len; + word32 sig; + int size; + int image_start, image_size; + int is_dir; + int block_size; + int map_blks; + int cur_blk; + + block_size = 512; + + cfg_free_alldirents(&g_cfg_partitionlist); + + blk_bufptr = (word32 *)malloc(MAX_PARTITION_BLK_SIZE); + + cfg_partition_read_block(fd, blk_bufptr, 0, block_size); + + driver_desc_ptr = (Driver_desc *)blk_bufptr; + sig = GET_BE_WORD16(driver_desc_ptr->sig); + block_size = GET_BE_WORD16(driver_desc_ptr->blk_size); + if(block_size == 0) { + block_size = 512; + } + if(sig != 0x4552 || block_size < 0x200 || + (block_size > MAX_PARTITION_BLK_SIZE)) { + cfg_printf("Partition error: No driver descriptor map found\n"); + free(blk_bufptr); + return 0; + } + + map_blks = 1; + cur_blk = 0; + size = cfg_get_fd_size(fd); + cfg_file_add_dirent(&g_cfg_partitionlist, "None - Whole image", + is_dir=0, size, 0, -1); + + while(cur_blk < map_blks) { + cur_blk++; + cfg_partition_read_block(fd, blk_bufptr, cur_blk, block_size); + part_map_ptr = (Part_map *)blk_bufptr; + sig = GET_BE_WORD16(part_map_ptr->sig); + if(cur_blk <= 1) { + map_blks = MIN(20, + GET_BE_WORD32(part_map_ptr->map_blk_cnt)); + } + if(sig != 0x504d) { + printf("Partition entry %d bad sig\n", cur_blk); + free(blk_bufptr); + return g_cfg_partitionlist.last; + } + + /* found it, check for consistency */ + start = GET_BE_WORD32(part_map_ptr->phys_part_start); + len = GET_BE_WORD32(part_map_ptr->part_blk_cnt); + data_off = GET_BE_WORD32(part_map_ptr->data_start); + data_len = GET_BE_WORD32(part_map_ptr->data_cnt); + if(data_off + data_len > len) { + printf("Poorly formed entry\n"); + continue; + } + + if(data_len < 10 || start < 1) { + printf("Poorly formed entry %d, datalen:%d, " + "start:%08x\n", cur_blk, data_len, start); + continue; + } + + image_size = data_len * block_size; + image_start = (start + data_off) * block_size; + is_dir = 2*(image_size < 800*1024); +#if 0 + printf(" partition add entry %d = %s %d %08x %08x\n", + cur_blk, part_map_ptr->part_name, is_dir, + image_size, image_start); +#endif + + cfg_file_add_dirent(&g_cfg_partitionlist, + part_map_ptr->part_name, is_dir, image_size, + image_start, cur_blk); + } + + free(blk_bufptr); + return g_cfg_partitionlist.last; +} + +int +cfg_maybe_insert_disk(int slot, int drive, const char *namestr) +{ + int num_parts; + int fd; + + fd = open(namestr, O_RDONLY | O_BINARY, 0x1b6); + if(fd < 0) { + printf("Cannot open: %s\n", namestr); + return 0; + } + + num_parts = cfg_partition_make_list(fd); + close(fd); + + if(num_parts > 0) { + printf("Choose a partition\n"); + g_cfg_select_partition = 1; + } else { + insert_disk(slot, drive, namestr, 0, 0, 0, -1); + return 1; + } + return 0; +} + +int +cfg_stat(char *path, struct stat *sb) +{ + int removed_slash; + int len; + int ret; + + removed_slash = 0; + len = 0; + +#ifdef _WIN32 + /* Windows doesn't like to stat paths ending in a /, so remove it */ + len = strlen(path); + if((len > 1) && (path[len - 1] == '/') ) { + path[len - 1] = 0; /* remove the slash */ + removed_slash = 1; + } +#endif + + ret = stat(path, sb); + +#ifdef _WIN32 + /* put the slash back */ + if(removed_slash) { + path[len - 1] = '/'; + } +#endif + + return ret; +} + +void +cfg_htab_vtab(int x, int y) +{ + if(x > 79) { + x = 0; + } + if(y > 23) { + y = 0; + } + g_cfg_curs_x = x; + g_cfg_curs_y = y; + g_cfg_curs_inv = 0; + g_cfg_curs_mousetext = 0; +} + +void +cfg_home() +{ + int i; + + cfg_htab_vtab(0, 0); + for(i = 0; i < 24; i++) { + cfg_cleol(); + } +} + +void +cfg_cleol() +{ + g_cfg_curs_inv = 0; + g_cfg_curs_mousetext = 0; + cfg_putchar(' '); + while(g_cfg_curs_x != 0) { + cfg_putchar(' '); + } +} + +void +cfg_putchar(int c) +{ + int offset; + int x, y; + + if(c == '\n') { + cfg_cleol(); + return; + } + if(c == '\b') { + g_cfg_curs_inv = !g_cfg_curs_inv; + return; + } + if(c == '\t') { + g_cfg_curs_mousetext = !g_cfg_curs_mousetext; + return; + } + y = g_cfg_curs_y; + x = g_cfg_curs_x; + + offset = g_screen_index[g_cfg_curs_y]; + if((x & 1) == 0) { + offset += 0x10000; + } + if(g_cfg_curs_inv) { + if(c >= 0x40 && c < 0x60) { + c = c & 0x1f; + } + } else { + c = c | 0x80; + } + if(g_cfg_curs_mousetext) { + c = (c & 0x1f) | 0x40; + } + set_memory_c(0xe00400 + offset + (x >> 1), c, 0); + x++; + if(x >= 80) { + x = 0; + y++; + if(y >= 24) { + y = 0; + } + } + g_cfg_curs_y = y; + g_cfg_curs_x = x; +} + +void +cfg_printf(const char *fmt, ...) +{ + va_list ap; + int c; + int i; + + va_start(ap, fmt); + (void)vsnprintf(g_cfg_printf_buf, CFG_PRINTF_BUFSIZE, fmt, ap); + va_end(ap); + + for(i = 0; i < CFG_PRINTF_BUFSIZE; i++) { + c = g_cfg_printf_buf[i]; + if(c == 0) { + return; + } + cfg_putchar(c); + } +} + +void +cfg_print_num(int num, int max_len) +{ + char buf[64]; + char buf2[64]; + int len; + int cnt; + int c; + int i, j; + + /* Prints right-adjusted "num" in field "max_len" wide */ + snprintf(&buf[0], 64, "%d", num); + len = strlen(buf); + for(i = 0; i < 64; i++) { + buf2[i] = ' '; + } + j = max_len + 1; + buf2[j] = 0; + j--; + cnt = 0; + for(i = len - 1; (i >= 0) && (j >= 1); i--) { + c = buf[i]; + if(c >= '0' && c <= '9') { + if(cnt >= 3) { + buf2[j--] = ','; + cnt = 0; + } + cnt++; + } + buf2[j--] = c; + } + cfg_printf(&buf2[1]); +} + +void +cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras) +{ + Disk *dsk; + int slot, drive; + + slot = type_ext >> 8; + drive = type_ext & 0xff; + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + + outstr[0] = 0; + if(dsk->name_ptr == 0) { + return; + } + + config_generate_config_kegs_name(outstr, maxlen, dsk, with_extras); +} + +void +cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change) +{ + char valbuf[CFG_OPT_MAXSTR]; + const char *menustr; + char *str; + char *outstr; + int *iptr; + int val; + int num_opts; + int opt_num; + int bufpos, outpos; + int curval, defval; + int type; + int type_ext; + int opt_get_str; + int separator; + int len; + int c; + int i; + + g_cfg_opt_buf[0] = 0; + + num_opts = 0; + opt_get_str = 0; + separator = ','; + + menu_ptr += menu_pos; /* move forward to entry menu_pos */ + + menustr = menu_ptr->str; + type = menu_ptr->cfgtype; + type_ext = (type >> 4); + type = type & 0xf; + len = strlen(menustr) + 1; + + bufpos = 0; + outstr = &(g_cfg_opt_buf[0]); + + outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; + outstr[bufpos++] = '\t'; + outstr[bufpos++] = '\t'; + outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; + + if(menu_pos == highlight_pos) { + outstr[bufpos++] = '\b'; + } + + opt_get_str = 2; + i = -1; + outpos = bufpos; +#if 0 + printf("cfg menu_pos: %d str len: %d\n", menu_pos, len); +#endif + while(++i < len) { + c = menustr[i]; + if(c == separator) { + if(i == 0) { + continue; + } + c = 0; + } + outstr[outpos++] = c; + outstr[outpos] = 0; + if(outpos >= CFG_OPT_MAXSTR) { + fprintf(stderr, "CFG_OPT_MAXSTR exceeded\n"); + my_exit(1); + } + if(c == 0) { + if(opt_get_str == 2) { + outstr = &(valbuf[0]); + bufpos = outpos - 1; + opt_get_str = 0; + } else if(opt_get_str) { +#if 0 + if(menu_pos == highlight_pos) { + printf("menu_pos %d opt %d = %s=%d\n", + menu_pos, num_opts, + g_cfg_opts_strs[num_opts], + g_cfg_opts_vals[num_opts]); + } +#endif + num_opts++; + outstr = &(valbuf[0]); + opt_get_str = 0; + if(num_opts >= CFG_MAX_OPTS) { + fprintf(stderr, "CFG_MAX_OPTS oflow\n"); + my_exit(1); + } + } else { + val = strtoul(valbuf, 0, 0); + g_cfg_opts_vals[num_opts] = val; + outstr = &(g_cfg_opts_strs[num_opts][0]); + opt_get_str = 1; + } + outpos = 0; + outstr[0] = 0; + } + } + + if(menu_pos == highlight_pos) { + g_cfg_opt_buf[bufpos++] = '\b'; + } + + g_cfg_opt_buf[bufpos] = 0; + + // Figure out if we should get a checkmark + curval = -1; + defval = -1; + if(type == CFGTYPE_INT) { + iptr = menu_ptr->ptr; + curval = *iptr; + iptr = menu_ptr->defptr; + defval = *iptr; + if(curval == defval) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + } + + // Decide what to display on the "right" side + str = 0; + opt_num = -1; + if(type == CFGTYPE_INT) { + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos++] = '='; + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos] = 0; + for(i = 0; i < num_opts; i++) { + if(curval == g_cfg_opts_vals[i]) { + opt_num = i; + break; + } + } + } + + if(change != 0) { + if(type == CFGTYPE_INT) { + if(num_opts > 0) { + opt_num += change; + if(opt_num >= num_opts) { + opt_num = 0; + } + if(opt_num < 0) { + opt_num = num_opts - 1; + } + curval = g_cfg_opts_vals[opt_num]; + } else { + curval += change; + /* HACK: min_val, max_val testing here */ + } + iptr = (int *)menu_ptr->ptr; + *iptr = curval; + } + g_config_kegs_update_needed = 1; + } + +#if 0 + if(menu_pos == highlight_pos) { + printf("menu_pos %d opt_num %d\n", menu_pos, opt_num); + } +#endif + + if(opt_num >= 0) { + str = &(g_cfg_opts_strs[opt_num][0]); + } else { + if(type == CFGTYPE_INT) { + str = &(g_cfg_opts_strs[0][0]); + snprintf(str, CFG_OPT_MAXSTR, "%d", curval); + } else if (type == CFGTYPE_DISK) { + str = &(g_cfg_opts_strs[0][0]), + cfg_get_disk_name(str, CFG_OPT_MAXSTR, type_ext, 1); + str = cfg_shorten_filename(str, 70); + } else { + str = ""; + } + } + +#if 0 + if(menu_pos == highlight_pos) { + printf("menu_pos %d buf_pos %d, str is %s, %02x, %02x, " + "%02x %02x\n", + menu_pos, bufpos, str, g_cfg_opt_buf[bufpos-1], + g_cfg_opt_buf[bufpos-2], + g_cfg_opt_buf[bufpos-3], + g_cfg_opt_buf[bufpos-4]); + } +#endif + + g_cfg_opt_buf[bufpos] = 0; + strncpy(&(g_cfg_opt_buf[bufpos]), str, CFG_OPT_MAXSTR - bufpos - 1); + g_cfg_opt_buf[CFG_OPT_MAXSTR-1] = 0; +} + +void +cfg_get_base_path(char *pathptr, const char *inptr, int go_up) +{ + const char *tmpptr; + char *slashptr; + char *outptr; + int add_dotdot, is_dotdot; + int len; + int c; + + /* Take full filename, copy it to pathptr, and truncate at last slash */ + /* inptr and pathptr can be the same */ + /* if go_up is set, then replace a blank dir with ".." */ + /* but first, see if path is currently just ../ over and over */ + /* if so, just tack .. onto the end and return */ + //printf("cfg_get_base start with %s\n", inptr); + + g_cfg_file_match[0] = 0; + tmpptr = inptr; + is_dotdot = 1; + while(1) { + if(tmpptr[0] == 0) { + break; + } + if(tmpptr[0] == '.' && tmpptr[1] == '.' && tmpptr[2] == '/') { + tmpptr += 3; + } else { + is_dotdot = 0; + break; + } + } + slashptr = 0; + outptr = pathptr; + c = -1; + while(c != 0) { + c = *inptr++; + if(c == '/') { + if(*inptr != 0) { /* if not a trailing slash... */ + slashptr = outptr; + } + } + *outptr++ = c; + } + if(!go_up) { + /* if not go_up, copy chopped part to g_cfg_file_match*/ + /* copy from slashptr+1 to end */ + tmpptr = slashptr+1; + if(slashptr == 0) { + tmpptr = pathptr; + } + strncpy(&g_cfg_file_match[0], tmpptr, CFG_PATH_MAX); + /* remove trailing / from g_cfg_file_match */ + len = strlen(&g_cfg_file_match[0]); + if((len > 1) && (len < (CFG_PATH_MAX - 1)) && + g_cfg_file_match[len - 1] == '/') { + g_cfg_file_match[len - 1] = 0; + } + //printf("set g_cfg_file_match to %s\n", &g_cfg_file_match[0]); + } + if(!is_dotdot && (slashptr != 0)) { + slashptr[0] = '/'; + slashptr[1] = 0; + outptr = slashptr + 2; + } + add_dotdot = 0; + if(pathptr[0] == 0 || is_dotdot) { + /* path was blank, or consisted of just ../ pattern */ + if(go_up) { + add_dotdot = 1; + } + } else if(slashptr == 0) { + /* no slashes found, but path was not blank--make it blank */ + if(pathptr[0] == '/') { + pathptr[1] = 0; + } else { + pathptr[0] = 0; + } + } + + if(add_dotdot) { + --outptr; + outptr[0] = '.'; + outptr[1] = '.'; + outptr[2] = '/'; + outptr[3] = 0; + } + + //printf("cfg_get_base end with %s, is_dotdot:%d, add_dotdot:%d\n", + // pathptr, is_dotdot, add_dotdot); +} + +void +cfg_file_init() +{ + int slot, drive; + int i; + + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, g_cfg_slotdrive, 0); + + slot = g_cfg_slotdrive >> 8; + drive = g_cfg_slotdrive & 1; + for(i = 0; i < 6; i++) { + if(g_cfg_tmp_path[0] != 0) { + break; + } + /* try to get a starting path from some mounted drive */ + drive = !drive; + if(i & 1) { + slot++; + if(slot >= 8) { + slot = 5; + } + } + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, + (slot << 8) + drive, 0); + } + cfg_get_base_path(&g_cfg_file_curpath[0], &g_cfg_tmp_path[0], 0); + g_cfg_dirlist.invalid = 1; +} + +void +cfg_free_alldirents(Cfg_listhdr *listhdrptr) +{ + int i; + + if(listhdrptr->max > 0) { + // Free the old directory listing + for(i = 0; i < listhdrptr->last; i++) { + free(listhdrptr->direntptr[i].name); + } + free(listhdrptr->direntptr); + } + + listhdrptr->direntptr = 0; + listhdrptr->last = 0; + listhdrptr->max = 0; + listhdrptr->invalid = 0; + + listhdrptr->topent = 0; + listhdrptr->curent = 0; +} + + +void +cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, + int size, int image_start, int part_num) +{ + Cfg_dirent *direntptr; + char *ptr; + int inc_amt; + int namelen; + + namelen = strlen(nameptr); + if(listhdrptr->last >= listhdrptr->max) { + // realloc + inc_amt = MAX(64, listhdrptr->max); + inc_amt = MIN(inc_amt, 1024); + listhdrptr->max += inc_amt; + listhdrptr->direntptr = realloc(listhdrptr->direntptr, + listhdrptr->max * sizeof(Cfg_dirent)); + } + ptr = malloc(namelen+1+is_dir); + strncpy(ptr, nameptr, namelen+1); + if(is_dir) { + strcat(ptr, "/"); + } +#if 0 + printf("...file entry %d is %s\n", g_cfg_dirlist.last, ptr); +#endif + direntptr = &(listhdrptr->direntptr[listhdrptr->last]); + direntptr->name = ptr; + direntptr->is_dir = is_dir; + direntptr->size = size; + direntptr->image_start = image_start; + direntptr->part_num = part_num; + listhdrptr->last++; +} + +int +cfg_dirent_sortfn(const void *obj1, const void *obj2) +{ + const Cfg_dirent *direntptr1, *direntptr2; + + /* Called by qsort to sort directory listings */ + direntptr1 = (const Cfg_dirent *)obj1; + direntptr2 = (const Cfg_dirent *)obj2; + return strcmp(direntptr1->name, direntptr2->name); +} + +int +cfg_str_match(const char *str1, const char *str2, int len) +{ + const byte *bptr1, *bptr2; + int c, c2; + int i; + + /* basically, work like strcmp, except if str1 ends first, return 0 */ + + bptr1 = (const byte *)str1; + bptr2 = (const byte *)str2; + for(i = 0; i < len; i++) { + c = *bptr1++; + c2 = *bptr2++; + if(c == 0) { + if(i > 0) { + return 0; + } else { + return c - c2; + } + } + if(c != c2) { + return c - c2; + } + } + + return 0; +} + +void +cfg_file_readdir(const char *pathptr) +{ + struct dirent *direntptr; + struct stat stat_buf; + DIR *dirptr; + mode_t fmt; + char *str; + const char *tmppathptr; + int ret; + int is_dir, is_gz; + int len; + int i; + + if(!strncmp(pathptr, &g_cfg_file_cachedpath[0], CFG_PATH_MAX) && + (g_cfg_dirlist.last > 0) && (g_cfg_dirlist.invalid==0)){ + return; + } + // No match, must read new directory + + // Free all dirents that were cached previously + cfg_free_alldirents(&g_cfg_dirlist); + + strncpy(&g_cfg_file_cachedpath[0], pathptr, CFG_PATH_MAX); + strncpy(&g_cfg_file_cachedreal[0], pathptr, CFG_PATH_MAX); + + str = &g_cfg_file_cachedreal[0]; + + for(i = 0; i < 200; i++) { + len = strlen(str); + if(len <= 0) { + break; + } else if(len < CFG_PATH_MAX-2) { + if(str[len-1] != '/') { + // append / to make various routines work + str[len] = '/'; + str[len+1] = 0; + } + } + ret = cfg_stat(str, &stat_buf); + is_dir = 0; + if(ret == 0) { + fmt = stat_buf.st_mode & S_IFMT; + if(fmt == S_IFDIR) { + /* it's a directory */ + is_dir = 1; + } + } + if(is_dir) { + break; + } else { + // user is entering more path, use base for display + cfg_get_base_path(str, str, 0); + } + } + + tmppathptr = str; + if(str[0] == 0) { + tmppathptr = "."; + } + cfg_file_add_dirent(&g_cfg_dirlist, "..", 1, 0, -1, -1); + + dirptr = opendir(tmppathptr); + if(dirptr == 0) { + printf("Could not open %s as a directory\n", tmppathptr); + return; + } + while(1) { + direntptr = readdir(dirptr); + if(direntptr == 0) { + break; + } + if(!strcmp(".", direntptr->d_name)) { + continue; + } + if(!strcmp("..", direntptr->d_name)) { + continue; + } + /* Else, see if it is a directory or a file */ + snprintf(&g_cfg_tmp_path[0], CFG_PATH_MAX, "%s%s", + &g_cfg_file_cachedreal[0], direntptr->d_name); + ret = cfg_stat(&g_cfg_tmp_path[0], &stat_buf); + len = strlen(g_cfg_tmp_path); + is_dir = 0; + is_gz = 0; + if((len > 3) && (strcmp(&g_cfg_tmp_path[len - 3], ".gz") == 0)){ + is_gz = 1; + } + if(ret != 0) { + printf("stat %s ret %d, errno:%d\n", &g_cfg_tmp_path[0], + ret, errno); + stat_buf.st_size = 0; + } else { + fmt = stat_buf.st_mode & S_IFMT; + if(fmt == S_IFDIR) { + /* it's a directory */ + is_dir = 1; + } else if((fmt == S_IFREG) && (is_gz == 0) && + (stat_buf.st_size < 140*1024)) { + /* skip it */ + continue; + } + } + cfg_file_add_dirent(&g_cfg_dirlist, direntptr->d_name, is_dir, + stat_buf.st_size, -1, -1); + } + + /* then sort the results (Mac's HFS+ is sorted, but other FS won't be)*/ + qsort(&(g_cfg_dirlist.direntptr[0]), g_cfg_dirlist.last, + sizeof(Cfg_dirent), cfg_dirent_sortfn); + + g_cfg_dirlist.curent = g_cfg_dirlist.last - 1; + for(i = g_cfg_dirlist.last - 1; i >= 0; i--) { + ret = cfg_str_match(&g_cfg_file_match[0], + g_cfg_dirlist.direntptr[i].name, CFG_PATH_MAX); + if(ret <= 0) { + /* set cur ent to closest filename to the match name */ + g_cfg_dirlist.curent = i; + } + } +} + +char * +cfg_shorten_filename(const char *in_ptr, int maxlen) +{ + char *out_ptr; + int len; + int c; + int i; + + /* Warning: uses a static string, not reentrant! */ + + out_ptr = &(g_cfg_file_shortened[0]); + len = strlen(in_ptr); + maxlen = MIN(len, maxlen); + for(i = 0; i < maxlen; i++) { + c = in_ptr[i] & 0x7f; + if(c < 0x20) { + c = '*'; + } + out_ptr[i] = c; + } + out_ptr[maxlen] = 0; + if(len > maxlen) { + for(i = 0; i < (maxlen/2); i++) { + c = in_ptr[len-i-1] & 0x7f; + if(c < 0x20) { + c = '*'; + } + out_ptr[maxlen-i-1] = c; + } + out_ptr[(maxlen/2) - 1] = '.'; + out_ptr[maxlen/2] = '.'; + out_ptr[(maxlen/2) + 1] = '.'; + } + + return out_ptr; +} + +void +cfg_fix_topent(Cfg_listhdr *listhdrptr) +{ + int num_to_show; + + num_to_show = listhdrptr->num_to_show; + + /* Force curent and topent to make sense */ + if(listhdrptr->curent >= listhdrptr->last) { + listhdrptr->curent = listhdrptr->last - 1; + } + if(listhdrptr->curent < 0) { + listhdrptr->curent = 0; + } + if(abs(listhdrptr->curent - listhdrptr->topent) >= num_to_show) { + listhdrptr->topent = listhdrptr->curent - (num_to_show/2); + } + if(listhdrptr->topent > listhdrptr->curent) { + listhdrptr->topent = listhdrptr->curent - (num_to_show/2); + } + if(listhdrptr->topent < 0) { + listhdrptr->topent = 0; + } +} + +void +cfg_file_draw() +{ + Cfg_listhdr *listhdrptr; + Cfg_dirent *direntptr; + char *str, *fmt; + int num_to_show; + int yoffset; + int x, y; + int i; + + cfg_file_readdir(&g_cfg_file_curpath[0]); + + for(y = 0; y < 21; y++) { + cfg_htab_vtab(0, y); + cfg_printf("\tZ\t"); + for(x = 1; x < 72; x++) { + cfg_htab_vtab(x, y); + cfg_putchar(' '); + } + cfg_htab_vtab(79, y); + cfg_printf("\t_\t"); + } + + cfg_htab_vtab(1, 0); + cfg_putchar('\b'); + for(x = 1; x < 79; x++) { + cfg_putchar(' '); + } + cfg_htab_vtab(30, 0); + cfg_printf("\bSelect image for s%dd%d\b", (g_cfg_slotdrive >> 8), + (g_cfg_slotdrive & 0xff) + 1); + + cfg_htab_vtab(2, 1); + cfg_printf("Current KEGS directory: %-50s", + cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); + + cfg_htab_vtab(2, 2); + cfg_printf("config.kegs path: %-50s", + cfg_shorten_filename(&g_config_kegs_name[0], 50)); + + cfg_htab_vtab(2, 3); + + str = ""; + if(g_cfg_file_pathfield) { + str = "\b \b"; + } + cfg_printf("Path: %s%s", + cfg_shorten_filename(&g_cfg_file_curpath[0], 64), str); + + cfg_htab_vtab(0, 4); + cfg_printf(" \t"); + for(x = 1; x < 79; x++) { + cfg_putchar('\\'); + } + cfg_printf("\t "); + + + /* Force curent and topent to make sense */ + listhdrptr = &g_cfg_dirlist; + num_to_show = CFG_NUM_SHOWENTS; + yoffset = 5; + if(g_cfg_select_partition > 0) { + listhdrptr = &g_cfg_partitionlist; + num_to_show -= 2; + cfg_htab_vtab(2, yoffset); + cfg_printf("Select partition of %-50s\n", + cfg_shorten_filename(&g_cfg_file_path[0], 50), str); + yoffset += 2; + } + + listhdrptr->num_to_show = num_to_show; + cfg_fix_topent(listhdrptr); + for(i = 0; i < num_to_show; i++) { + y = i + yoffset; + if(listhdrptr->last > (i + listhdrptr->topent)) { + direntptr = &(listhdrptr-> + direntptr[i + listhdrptr->topent]); + cfg_htab_vtab(2, y); + if(direntptr->is_dir) { + cfg_printf("\tXY\t "); + } else { + cfg_printf(" "); + } + if(direntptr->part_num >= 0) { + cfg_printf("%3d: ", direntptr->part_num); + } + str = cfg_shorten_filename(direntptr->name, 45); + fmt = "%-45s"; + if(i + listhdrptr->topent == listhdrptr->curent) { + if(g_cfg_file_pathfield == 0) { + fmt = "\b%-45s\b"; + } else { + fmt = "%-44s\b \b"; + } + } + cfg_printf(fmt, str); + if(!direntptr->is_dir) { + cfg_print_num(direntptr->size, 13); + } + } + } + + cfg_htab_vtab(1, 21); + cfg_putchar('\t'); + for(x = 1; x < 79; x++) { + cfg_putchar('L'); + } + cfg_putchar('\t'); + +} + +void +cfg_partition_selected() +{ + char *str; + const char *part_str; + char *part_str2; + int pos; + int part_num; + + pos = g_cfg_partitionlist.curent; + str = g_cfg_partitionlist.direntptr[pos].name; + part_num = -2; + part_str = 0; + if(str[0] == 0 || (str[0] >= '0' && str[0] <= '9')) { + part_num = g_cfg_partitionlist.direntptr[pos].part_num; + } else { + part_str = str; + } + part_str2 = 0; + if(part_str != 0) { + part_str2 = (char *)malloc(strlen(part_str)+1); + strcpy(part_str2, part_str); + } + + insert_disk(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff, + &(g_cfg_file_path[0]), 0, 0, part_str2, part_num); + if(part_str2 != 0) { + free(part_str2); + } + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; +} + +void +cfg_file_selected() +{ + struct stat stat_buf; + char *str; + int fmt; + int ret; + + if(g_cfg_select_partition > 0) { + cfg_partition_selected(); + return; + } + + if(g_cfg_file_pathfield == 0) { + // in file section area of window + str = g_cfg_dirlist.direntptr[g_cfg_dirlist.curent].name; + if(!strcmp(str, "../")) { + /* go up one directory */ + cfg_get_base_path(&g_cfg_file_curpath[0], + &g_cfg_file_curpath[0], 1); + return; + } + + snprintf(&g_cfg_file_path[0], CFG_PATH_MAX, "%s%s", + &g_cfg_file_cachedreal[0], str); + } else { + // just use cfg_file_curpath directly + strncpy(&g_cfg_file_path[0], &g_cfg_file_curpath[0], + CFG_PATH_MAX); + } + + ret = cfg_stat(&g_cfg_file_path[0], &stat_buf); + fmt = stat_buf.st_mode & S_IFMT; + cfg_printf("Stat'ing %s, st_mode is: %08x\n", &g_cfg_file_path[0], + (int)stat_buf.st_mode); + + if(ret != 0) { + printf("stat %s returned %d, errno: %d\n", &g_cfg_file_path[0], + ret, errno); + } else { + if(fmt == S_IFDIR) { + /* it's a directory */ + strncpy(&g_cfg_file_curpath[0], &g_cfg_file_path[0], + CFG_PATH_MAX); + } else { + /* select it */ + ret = cfg_maybe_insert_disk(g_cfg_slotdrive >> 8, + g_cfg_slotdrive & 0xff, &g_cfg_file_path[0]); + if(ret > 0) { + g_cfg_slotdrive = -1; + } + } + } +} + +void +cfg_file_handle_key(int key) +{ + Cfg_listhdr *listhdrptr; + int len; + + if(g_cfg_file_pathfield) { + if(key >= 0x20 && key < 0x7f) { + len = strlen(&g_cfg_file_curpath[0]); + if(len < CFG_PATH_MAX-4) { + g_cfg_file_curpath[len] = key; + g_cfg_file_curpath[len+1] = 0; + } + return; + } + } + + listhdrptr = &g_cfg_dirlist; + if(g_cfg_select_partition > 0) { + listhdrptr = &g_cfg_partitionlist; + } + if( (g_cfg_file_pathfield == 0) && + ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) ) { + /* jump to file starting with this letter */ + g_cfg_file_match[0] = key; + g_cfg_file_match[1] = 0; + g_cfg_dirlist.invalid = 1; /* re-read directory */ + } + + switch(key) { + case 0x1b: + eject_disk_by_num(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff); + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; + g_cfg_dirlist.invalid = 1; + break; + case 0x0a: /* down arrow */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent++; + cfg_fix_topent(listhdrptr); + } + break; + case 0x0b: /* up arrow */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent--; + cfg_fix_topent(listhdrptr); + } + break; + case 0x0d: /* return */ + cfg_file_selected(); + break; + case 0x09: /* tab */ + g_cfg_file_pathfield = !g_cfg_file_pathfield; + break; + case 0x08: /* left arrow */ + case 0x7f: /* delete key */ + if(g_cfg_file_pathfield) { + // printf("left arrow/delete\n"); + len = strlen(&g_cfg_file_curpath[0]) - 1; + if(len >= 0) { + g_cfg_file_curpath[len] = 0; + } + } + break; + default: + printf("key: %02x\n", key); + } +#if 0 + printf("curent: %d, topent: %d, last: %d\n", + g_cfg_dirlist.curent, g_cfg_dirlist.topent, g_cfg_dirlist.last); +#endif +} + +void +config_control_panel() +{ + void (*fn_ptr)(); + const char *str; + Cfg_menu *menu_ptr; + void *ptr; + int print_eject_help; + int line; + int type; + int match_found; + int menu_line; + int menu_inc; + int max_line; + int key; + int i, j; + + // First, save key text info + g_save_cur_a2_stat = g_cur_a2_stat; + for(i = 0; i < 0x400; i++) { + g_save_text_screen_bytes[i] = g_slow_memory_ptr[0x400+i]; + g_save_text_screen_bytes[0x400+i] =g_slow_memory_ptr[0x10400+i]; + } + + g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_VID80 | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR) | ALL_STAT_ALTCHARSET; + g_a2_new_all_stat[0] = g_cur_a2_stat; + g_new_a2_stat_cur_line = 0; + + cfg_printf("In config_control_panel\n"); + + for(i = 0; i < 20; i++) { + if(adb_read_c000() & 0x80) { + (void)adb_access_c010(); + } + } + g_adb_repeat_vbl = 0; + g_cfg_vbl_count = 0; + // HACK: Force adb keyboard (and probably mouse) to "normal"... + + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + + cfg_home(); + j = 0; + + menu_ptr = g_cfg_main_menu; + menu_line = 1; + menu_inc = 1; + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; + + while(g_config_control_panel) { + cfg_home(); + line = 1; + max_line = 1; + match_found = 0; + print_eject_help = 0; + cfg_printf("%s\n\n", menu_ptr[0].str); + while(line < 24) { + str = menu_ptr[line].str; + type = menu_ptr[line].cfgtype; + ptr = menu_ptr[line].ptr; + if(str == 0) { + break; + } + if((type & 0xf) == CFGTYPE_DISK) { + print_eject_help = 1; + } + cfg_parse_menu(menu_ptr, line, menu_line, 0); + if(line == menu_line) { + if(type != 0) { + match_found = 1; + } else if(menu_inc) { + menu_line++; + } else { + menu_line--; + } + } + if(line > max_line) { + max_line = line; + } + + cfg_printf("%s\n", g_cfg_opt_buf); + line++; + } + if((menu_line < 1) && !match_found) { + menu_line = 1; + } + if((menu_line >= max_line) && !match_found) { + menu_line = max_line; + } + + cfg_htab_vtab(0, 23); + cfg_printf("Move: \tJ\t \tK\t Change: \tH\t \tU\t \tM\t"); + if(print_eject_help) { + cfg_printf(" Eject: "); + if(g_cfg_slotdrive >= 0) { + cfg_printf("\bESC\b"); + } else { + cfg_printf("E"); + } + } +#if 0 + cfg_htab_vtab(0, 22); + cfg_printf("menu_line: %d line: %d, vbl:%d, adb:%d key_dn:%d\n", + menu_line, line, g_cfg_vbl_count, g_adb_repeat_vbl, + g_key_down); +#endif + + if(g_cfg_slotdrive >= 0) { + cfg_file_draw(); + } + + key = -1; + while(g_config_control_panel) { + video_update(); + key = adb_read_c000(); + if(key & 0x80) { + key = key & 0x7f; + (void)adb_access_c010(); + break; + } else { + key = -1; + } + micro_sleep(1.0/60.0); + g_cfg_vbl_count++; + if(!match_found) { + break; + } + } + + if((key >= 0) && (g_cfg_slotdrive < 0)) { + // Normal menu system + switch(key) { + case 0x0a: /* down arrow */ + menu_line++; + menu_inc = 1; + break; + case 0x0b: /* up arrow */ + menu_line--; + menu_inc = 0; + if(menu_line < 1) { + menu_line = 1; + } + break; + case 0x15: /* right arrow */ + cfg_parse_menu(menu_ptr, menu_line,menu_line,1); + break; + case 0x08: /* left arrow */ + cfg_parse_menu(menu_ptr,menu_line,menu_line,-1); + break; + case 0x0d: + type = menu_ptr[menu_line].cfgtype; + ptr = menu_ptr[menu_line].ptr; + switch(type & 0xf) { + case CFGTYPE_MENU: + menu_ptr = (Cfg_menu *)ptr; + menu_line = 1; + break; + case CFGTYPE_DISK: + g_cfg_slotdrive = type >> 4; + cfg_file_init(); + break; + case CFGTYPE_FUNC: + fn_ptr = (void (*)())ptr; + (*fn_ptr)(); + break; + } + break; + case 0x1b: + // Jump to last menu entry + menu_line = max_line; + break; + case 'e': + case 'E': + type = menu_ptr[menu_line].cfgtype; + if((type & 0xf) == CFGTYPE_DISK) { + eject_disk_by_num(type >> 12, + (type >> 4) & 0xff); + } + break; + default: + printf("key: %02x\n", key); + } + } else if(key >= 0) { + cfg_file_handle_key(key); + } + } + + for(i = 0; i < 0x400; i++) { + set_memory_c(0xe00400+i, g_save_text_screen_bytes[i], 0); + set_memory_c(0xe10400+i, g_save_text_screen_bytes[0x400+i], 0); + } + + // And quit + g_config_control_panel = 0; + g_adb_repeat_vbl = g_vbl_count + 60; + g_cur_a2_stat = g_save_cur_a2_stat; + change_display_mode(g_cur_dcycs); + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; +} + diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..06106dc --- /dev/null +++ b/src/config.h @@ -0,0 +1,34 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2003 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_config_h[] = "@(#)$KmKId: config.h,v 1.8 2003-10-17 15:09:58-04 kentd Exp $"; +#endif + +#define CONF_BUF_LEN 1024 +#define COPY_BUF_SIZE 4096 +#define CFG_PRINTF_BUFSIZE 2048 + +#define CFG_PATH_MAX 1024 + +#define CFG_NUM_SHOWENTS 16 + +#define CFGTYPE_MENU 1 +#define CFGTYPE_INT 2 +#define CFGTYPE_DISK 3 +#define CFGTYPE_FUNC 4 +/* CFGTYPE limited to just 4 bits: 0-15 */ + +/* Cfg_menu, Cfg_dirent and Cfg_listhdr are defined in defc.h */ + +STRUCT(Cfg_defval) { + Cfg_menu *menuptr; + int intval; +}; diff --git a/src/defc.h b/src/defc.h new file mode 100644 index 0000000..1596fe9 --- /dev/null +++ b/src/defc.h @@ -0,0 +1,265 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_defc_h[] = "@(#)$KmKId: defc.h,v 1.91 2003-11-03 01:29:38-05 kentd Exp $"; +#endif + +#include "defcomm.h" + +#define STRUCT(a) typedef struct _ ## a a; struct _ ## a + +typedef unsigned char byte; +typedef unsigned short word16; +typedef unsigned int word32; +#if _MSC_VER +typedef unsigned __int64 word64; +#else +typedef unsigned long long word64; +#endif + +void U_STACK_TRACE(); + +/* 28MHz crystal, plus every 65th 1MHz cycle is stretched 140ns */ +#define CYCS_28_MHZ (28636360) +#define DCYCS_28_MHZ (1.0*CYCS_28_MHZ) +#define CYCS_3_5_MHZ (CYCS_28_MHZ/8) +#define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0))) +#define CYCS_1_MHZ ((int)DCYCS_1_MHZ) + +#define DCYCS_IN_16MS_RAW (DCYCS_1_MHZ / 60.0) +#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW)) +#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS)) + +#ifdef KEGS_LITTLE_ENDIAN +# define BIGEND(a) ((((a) >> 24) & 0xff) + \ + (((a) >> 8) & 0xff00) + \ + (((a) << 8) & 0xff0000) + \ + (((a) << 24) & 0xff000000)) +# define GET_BE_WORD16(a) ((((a) >> 8) & 0xff) + (((a) << 8) & 0xff00)) +# define GET_BE_WORD32(a) (BIGEND(a)) +#else +# define BIGEND(a) (a) +# define GET_BE_WORD16(a) (a) +# define GET_BE_WORD32(a) (a) +#endif + +#define MAXNUM_HEX_PER_LINE 32 + +#ifdef __NeXT__ +# include +#endif + +#ifndef _WIN32 +# include +# include +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef HPUX +# include /* for GET_ITIMER */ +#endif + +#ifdef SOLARIS +# include +#endif + +#ifndef O_BINARY +/* work around some Windows junk */ +# define O_BINARY 0 +#endif + +STRUCT(Pc_log) { + double dcycs; + word32 dbank_kpc; + word32 instr; + word32 psr_acc; + word32 xreg_yreg; + word32 stack_direct; + word32 pad; +}; + +STRUCT(Event) { + double dcycs; + int type; + Event *next; +}; + +STRUCT(Fplus) { + double plus_1; + double plus_2; + double plus_3; + double plus_x_minus_1; +}; + +STRUCT(Engine_reg) { + double fcycles; + word32 kpc; + word32 acc; + + word32 xreg; + word32 yreg; + + word32 stack; + word32 dbank; + + word32 direct; + word32 psr; + Fplus *fplus_ptr; +}; + +STRUCT(Kimage) { + void *dev_handle; + void *dev_handle2; + byte *data_ptr; + int width_req; + int width_act; + int height; + int depth; + int mdepth; + int aux_info; +}; + +typedef byte *Pg_info; +STRUCT(Page_info) { + Pg_info rd_wr; +}; + +STRUCT(Cfg_menu) { + const char *str; + void *ptr; + const char *name_str; + void *defptr; + int cfgtype; +}; + +STRUCT(Cfg_dirent) { + char *name; + int is_dir; + int size; + int image_start; + int part_num; +}; + +STRUCT(Cfg_listhdr) { + Cfg_dirent *direntptr; + int max; + int last; + int invalid; + + int curent; + int topent; + + int num_to_show; +}; + +#ifdef __LP64__ +# define PTR2WORD(a) ((unsigned long)(a)) +#else +# define PTR2WORD(a) ((unsigned int)(a)) +#endif + + +#define ALTZP (statereg & 0x80) +#define PAGE2 (statereg & 0x40) +#define RAMRD (statereg & 0x20) +#define RAMWRT (statereg & 0x10) +#define RDROM (statereg & 0x08) +#define LCBANK2 (statereg & 0x04) +#define ROMB (statereg & 0x02) +#define INTCX (statereg & 0x01) + +#define EXTRU(val, pos, len) \ + ( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \ + (((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) ) + +#define DEP1(val, pos, old_val) \ + (((old_val) & ~(1 << (31 - (pos))) ) | \ + ( ((val) & 1) << (31 - (pos))) ) + +#define set_halt(val) \ + if(val) { set_halt_act(val); } + +#define clear_halt() \ + clr_halt_act() + +#define GET_PAGE_INFO_RD(page) \ + (page_info_rd_wr[page].rd_wr) + +#define GET_PAGE_INFO_WR(page) \ + (page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr) + +#define SET_PAGE_INFO_RD(page,val) \ + ;page_info_rd_wr[page].rd_wr = (Pg_info)val; + +#define SET_PAGE_INFO_WR(page,val) \ + ;page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr = \ + (Pg_info)val; + +#define VERBOSE_DISK 0x001 +#define VERBOSE_IRQ 0x002 +#define VERBOSE_CLK 0x004 +#define VERBOSE_SHADOW 0x008 +#define VERBOSE_IWM 0x010 +#define VERBOSE_DOC 0x020 +#define VERBOSE_ADB 0x040 +#define VERBOSE_SCC 0x080 +#define VERBOSE_TEST 0x100 +#define VERBOSE_VIDEO 0x200 +#define VERBOSE_MAC 0x400 + +#ifdef NO_VERB +# define DO_VERBOSE 0 +#else +# define DO_VERBOSE 1 +#endif + +#define disk_printf if(DO_VERBOSE && (Verbose & VERBOSE_DISK)) printf +#define irq_printf if(DO_VERBOSE && (Verbose & VERBOSE_IRQ)) printf +#define clk_printf if(DO_VERBOSE && (Verbose & VERBOSE_CLK)) printf +#define shadow_printf if(DO_VERBOSE && (Verbose & VERBOSE_SHADOW)) printf +#define iwm_printf if(DO_VERBOSE && (Verbose & VERBOSE_IWM)) printf +#define doc_printf if(DO_VERBOSE && (Verbose & VERBOSE_DOC)) printf +#define adb_printf if(DO_VERBOSE && (Verbose & VERBOSE_ADB)) printf +#define scc_printf if(DO_VERBOSE && (Verbose & VERBOSE_SCC)) printf +#define test_printf if(DO_VERBOSE && (Verbose & VERBOSE_TEST)) printf +#define vid_printf if(DO_VERBOSE && (Verbose & VERBOSE_VIDEO)) printf +#define mac_printf if(DO_VERBOSE && (Verbose & VERBOSE_MAC)) printf + + +#define HALT_ON_SCAN_INT 0x001 +#define HALT_ON_IRQ 0x002 +#define HALT_ON_SHADOW_REG 0x004 +#define HALT_ON_C70D_WRITES 0x008 + +#define HALT_ON(a, msg) \ + if(Halt_on & a) { \ + halt_printf(msg); \ + } + + +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +# define MAX(a,b) (((a) < (b)) ? (b) : (a)) +#endif + +#define GET_ITIMER(dest) dest = get_itimer(); + +#include "iwm.h" +#include "protos.h" diff --git a/src/defcomm.h b/src/defcomm.h new file mode 100644 index 0000000..7de1042 --- /dev/null +++ b/src/defcomm.h @@ -0,0 +1,200 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsdif_defcomm_h[] = "@(#)$KmKId: defcomm.h,v 1.93 2002-11-19 03:10:38-05 kadickey Exp $"; +#endif + +#define USE_XIMAGE_CHANGED + +#if 0 +# define CHECK_BREAKPOINTS +#endif + +#define SHIFT_PER_CHANGE 3 +#define CHANGE_SHIFT (5 + SHIFT_PER_CHANGE) + +#define SLOW_MEM_CH_SIZE (0x10000 >> CHANGE_SHIFT) + +#define MAXNUM_HEX_PER_LINE 32 + +/* Different Joystick defines */ +#define JOYSTICK_MOUSE 1 +#define JOYSTICK_LINUX 2 +#define JOYSTICK_KEYPAD 3 +#define JOYSTICK_WIN32_1 4 +#define JOYSTICK_WIN32_2 5 + + +#define HALT_EVENT 0x10 + +#define MAX_BREAK_POINTS 0x20 + +#define MAX_BP_INDEX 0x100 +#define MAX_BP_PER_INDEX 3 /* 4 word32s total = 16 bytes */ +#define SIZE_BREAKPT_ENTRY_BITS 4 /* 16 bytes = 4 bits */ + +/* Warning--next defines used by asm! */ +#define PAGE_INFO_PAD_SIZE 0x800 +#define PAGE_INFO_WR_OFFSET 0x10000+PAGE_INFO_PAD_SIZE + +#define BANK_IO_BIT 31 +#define BANK_SHADOW_BIT 30 +#define BANK_SHADOW2_BIT 29 +#define BANK_IO2_BIT 28 +#define BANK_BREAK_BIT 27 +#define BANK_BREAK (1 << (31 - BANK_BREAK_BIT)) +#define BANK_IO2_TMP (1 << (31 - BANK_IO2_BIT)) +#define BANK_IO_TMP (1 << (31 - BANK_IO_BIT)) +#define BANK_SHADOW (1 << (31 - BANK_SHADOW_BIT)) +#define BANK_SHADOW2 (1 << (31 - BANK_SHADOW2_BIT)) +#define SET_BANK_IO \ + (&g_dummy_memory1_ptr[BANK_IO_TMP | BANK_IO2_TMP]) + +#define BANK_BAD_MEM (&g_dummy_memory1_ptr[0xff]) + + +#define LEN_FIFO_BUF 160 +#define LEN_KBD_BUF 160 + +#define FIFO_OK 0x1 +#define FIFO_INIT 0x2 +#define FIFO_END 0x3 +#define FIFO_40COLS 0x4 +#define FIFO_80COLS 0x5 +#define FIFO_SENDCHAR 0x6 +#define FIFO_SENDKEY 0x7 +#define FIFO_REFRESH 0x8 + +#define B_OP_SIZE 2 +#define B_OP_D_SIZE 5 +#define B_OP_DTYPE 12 +#define SIZE_OP_DTYPE 7 + + + +#define ENGINE_FCYCLES 0x00 +#define ENGINE_REG_KPC 0x08 +#define ENGINE_REG_ACC 0x0c +#define ENGINE_REG_XREG 0x10 +#define ENGINE_REG_YREG 0x14 +#define ENGINE_REG_STACK 0x18 +#define ENGINE_REG_DBANK 0x1c +#define ENGINE_REG_DIRECT 0x20 +#define ENGINE_REG_PSR 0x24 +#define ENGINE_FPLUS_PTR 0x28 + +#define LOG_PC_DCYCS 0x00 +#define LOG_PC_DBANK_KPC 0x08 +#define LOG_PC_INSTR 0x0c +#define LOG_PC_PSR_ACC 0x10 +#define LOG_PC_XREG_YREG 0x14 +#define LOG_PC_STACK_DIRECT 0x18 +#define LOG_PC_PAD 0x1c + +#define LOG_PC_SIZE 0x20 + + +#define FPLUS_PLUS_1 0x00 +#define FPLUS_PLUS_2 0x08 +#define FPLUS_PLUS_3 0x10 +#define FPLUS_PLUS_X_M1 0x18 + +#define RET_BREAK 0x1 +#define RET_COP 0x2 +#define RET_WDM 0x3 +#define RET_MVP 0x4 +#define RET_MVN 0x5 +#define RET_WAI 0x6 +#define RET_STP 0x7 +#define RET_ADD_DEC_8 0x8 +#define RET_ADD_DEC_16 0x9 +#define RET_C700 0xa +#define RET_C70A 0xb +#define RET_C70D 0xc +#define RET_IRQ 0xd + + +#define MODE_BORDER 0 +#define MODE_TEXT 1 +#define MODE_GR 2 +#define MODE_HGR 3 +#define MODE_SUPER_HIRES 4 + +#define BIT_ALL_STAT_TEXT 0 +#define BIT_ALL_STAT_VID80 1 +#define BIT_ALL_STAT_ST80 2 +#define BIT_ALL_STAT_COLOR_C021 3 +#define BIT_ALL_STAT_MIX_T_GR 4 +#define BIT_ALL_STAT_DIS_COLOR_DHIRES 5 /* special val, c029 */ +#define BIT_ALL_STAT_PAGE2 6 /* special val, statereg */ +#define BIT_ALL_STAT_SUPER_HIRES 7 /* special, c029 */ +#define BIT_ALL_STAT_HIRES 8 +#define BIT_ALL_STAT_ANNUNC3 9 +#define BIT_ALL_STAT_BG_COLOR 10 /* 4 bits */ +#define BIT_ALL_STAT_TEXT_COLOR 14 /* 4 bits */ + /* Text must be just above */ + /* bg to match c022 reg */ +#define BIT_ALL_STAT_ALTCHARSET 18 +#define BIT_ALL_STAT_FLASH_STATE 19 +#define BIT_ALL_STAT_A2VID_PALETTE 20 /* 4 bits */ + +#define ALL_STAT_SUPER_HIRES (1 << (BIT_ALL_STAT_SUPER_HIRES)) +#define ALL_STAT_TEXT (1 << (BIT_ALL_STAT_TEXT)) +#define ALL_STAT_VID80 (1 << (BIT_ALL_STAT_VID80)) +#define ALL_STAT_PAGE2 (1 << (BIT_ALL_STAT_PAGE2)) +#define ALL_STAT_ST80 (1 << (BIT_ALL_STAT_ST80)) +#define ALL_STAT_COLOR_C021 (1 << (BIT_ALL_STAT_COLOR_C021)) +#define ALL_STAT_DIS_COLOR_DHIRES (1 << (BIT_ALL_STAT_DIS_COLOR_DHIRES)) +#define ALL_STAT_MIX_T_GR (1 << (BIT_ALL_STAT_MIX_T_GR)) +#define ALL_STAT_HIRES (1 << (BIT_ALL_STAT_HIRES)) +#define ALL_STAT_ANNUNC3 (1 << (BIT_ALL_STAT_ANNUNC3)) +#define ALL_STAT_TEXT_COLOR (0xf << (BIT_ALL_STAT_TEXT_COLOR)) +#define ALL_STAT_BG_COLOR (0xf << (BIT_ALL_STAT_BG_COLOR)) +#define ALL_STAT_ALTCHARSET (1 << (BIT_ALL_STAT_ALTCHARSET)) +#define ALL_STAT_FLASH_STATE (1 << (BIT_ALL_STAT_FLASH_STATE)) +#define ALL_STAT_A2VID_PALETTE (0xf << (BIT_ALL_STAT_A2VID_PALETTE)) + +#define BORDER_WIDTH 32 + +#define EFF_BORDER_WIDTH (BORDER_WIDTH + (640-560)) + +/* BASE_MARGIN_BOTTOM+MARGIN_TOP must equal 62. There are 262 scan lines */ +/* at 60Hz (15.7KHz line rate) and so we just make 62 border lines */ +#define BASE_MARGIN_TOP 32 +#define BASE_MARGIN_BOTTOM 30 +#define BASE_MARGIN_LEFT BORDER_WIDTH +#define BASE_MARGIN_RIGHT BORDER_WIDTH + +#define A2_WINDOW_WIDTH 640 +#define A2_WINDOW_HEIGHT 400 + +#define X_A2_WINDOW_WIDTH (A2_WINDOW_WIDTH + BASE_MARGIN_LEFT + \ + BASE_MARGIN_RIGHT) +#define X_A2_WINDOW_HEIGHT (A2_WINDOW_HEIGHT + BASE_MARGIN_TOP + \ + BASE_MARGIN_BOTTOM) + +#define MAX_STATUS_LINES 7 +#define STATUS_LINE_LENGTH 88 + +#define BASE_WINDOW_WIDTH (X_A2_WINDOW_WIDTH) + + +#define A2_BORDER_COLOR_NUM 0xfe + +#if 0 +#define A2_TEXT_COLOR_ALT_NUM 0x01 +#define A2_BG_COLOR_ALT_NUM 0x00 +#define A2_TEXT_COLOR_PRIM_NUM 0x02 +#define A2_BG_COLOR_PRIM_NUM 0x00 +#define A2_TEXT_COLOR_FLASH_NUM 0x0c +#define A2_BG_COLOR_FLASH_NUM 0x08 +#endif + diff --git a/src/defs.h b/src/defs.h new file mode 100644 index 0000000..161f968 --- /dev/null +++ b/src/defs.h @@ -0,0 +1,63 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_S + .data + .export rcsdif_defs_h,data +rcsdif_defs_h + .stringz "@(#)$KmKId: defs.h,v 1.22 2002-11-19 03:10:38-05 kadickey Exp $" + .code +#endif + +#include "defcomm.h" + +link .reg %r2 +acc .reg %r3 +xreg .reg %r4 +yreg .reg %r5 +stack .reg %r6 +dbank .reg %r7 +direct .reg %r8 +neg .reg %r9 +zero .reg %r10 +psr .reg %r11 +kpc .reg %r12 +const_fd .reg %r13 +instr .reg %r14 +#if 0 +cycles .reg %r13 +kbank .reg %r14 +#endif + +page_info_ptr .reg %r15 +inst_tab_ptr .reg %r16 +fcycles_stop_ptr .reg %r17 +addr_latch .reg %r18 + +scratch1 .reg %r19 +scratch2 .reg %r20 +scratch3 .reg %r21 +scratch4 .reg %r22 +;instr .reg %r23 ; arg3 + +fcycles .reg %fr12 +fr_plus_1 .reg %fr13 +fr_plus_2 .reg %fr14 +fr_plus_3 .reg %fr15 +fr_plus_x_m1 .reg %fr16 +fcycles_stop .reg %fr17 +fcycles_last_dcycs .reg %fr18 + +ftmp1 .reg %fr4 +ftmp2 .reg %fr5 +fscr1 .reg %fr6 + +#define LDC(val,reg) ldil L%val,reg ! ldo R%val(reg),reg + diff --git a/src/defs_instr.h b/src/defs_instr.h new file mode 100644 index 0000000..89a49c6 --- /dev/null +++ b/src/defs_instr.h @@ -0,0 +1,1622 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef ASM +# ifdef INCLUDE_RCSID_S + .data + .export rcsdif_defs_instr_h,data +rcsdif_defs_instr_h + .stringz "@(#)$KmKId: defs_instr.h,v 1.57 2004-01-10 15:49:14-05 kentd Exp $" + .code +# endif + +# ifdef ACC8 + .export defs_instr_start_8,data +defs_instr_start_8 .word 0 +# else + .export defs_instr_start_16,data +defs_instr_start_16 .word 0 +# endif /* ACC8*/ +#endif /* ASM */ + + +#undef GET_DLOC_X_IND_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_X_IND_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_X_IND_WR() ! \ + bl get_mem_long_8,link ! \ + nop +# else +# define GET_DLOC_X_IND_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_X_IND_WR() ! \ + bl get_mem_long_16,link ! \ + nop +# endif /* ACC8 */ +#else /* C*/ +# ifdef ACC8 +# define GET_DLOC_X_IND_RD() \ + GET_1BYTE_ARG; \ + GET_DLOC_X_IND_WR(); \ + GET_MEMORY8(arg, arg); +# else +# define GET_DLOC_X_IND_RD() \ + GET_1BYTE_ARG; \ + GET_DLOC_X_IND_WR(); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + +#undef GET_DISP8_S_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DISP8_S_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DISP8_S_WR() ! \ + bl get_mem_b0_8,link ! \ + nop +# else +# define GET_DISP8_S_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DISP8_S_WR() ! \ + bl get_mem_b0_16,link ! \ + nop +# endif +#else /* C */ +# ifdef ACC8 +# define GET_DISP8_S_RD() \ + GET_1BYTE_ARG; \ + GET_DISP8_S_WR(); \ + GET_MEMORY8(arg, arg); +# else +# define GET_DISP8_S_RD() \ + GET_1BYTE_ARG; \ + GET_DISP8_S_WR(); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + +#ifdef ASM +# define MUST_FIX \ + break +#endif + +#undef GET_DLOC_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_RD() \ + ldb 1(scratch1),arg0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + INC_KPC_2 ! \ + add direct,arg0,addr_latch ! \ + extru addr_latch,23,16,arg3 ! \ + CYCLES_PLUS_1 ! \ + ldwx,s arg3(page_info_ptr),scratch2 ! \ + extru addr_latch,31,8,scratch4 ! \ + extru addr_latch,31,16,addr_latch ! \ + ldbx scratch4(scratch2),ret0 ! \ + extru,= scratch2,BANK_IO_BIT,1,0 ! \ + bl get_memory_iocheck_stub_asm,link ! \ + copy addr_latch,arg0 +# else +# define GET_DLOC_RD() \ + ldb 1(scratch1),arg0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + INC_KPC_2 ! \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_16,link ! \ + extru arg0,31,16,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define GET_DLOC_RD() \ + GET_1BYTE_ARG; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + GET_MEMORY8((direct + arg) & 0xffff, arg); +# else +# define GET_DLOC_RD() \ + GET_1BYTE_ARG; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + GET_MEMORY16((direct + arg) & 0xffff, arg, 1); +# endif +#endif + + +#undef GET_DLOC_L_IND_RD +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_L_IND_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_L_IND_WR() ! \ + bl get_mem_long_8,link ! \ + nop +# else +# define GET_DLOC_L_IND_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_L_IND_WR() ! \ + bl get_mem_long_16,link ! \ + nop +# endif +#else /* C */ +# ifdef ACC8 +# define GET_DLOC_L_IND_RD() \ + GET_1BYTE_ARG; \ + GET_DLOC_L_IND_WR(); \ + GET_MEMORY8(arg, arg); +# else +# define GET_DLOC_L_IND_RD() \ + GET_1BYTE_ARG; \ + GET_DLOC_L_IND_WR(); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + +#undef GET_IMM_MEM + +#ifdef ASM +# ifdef ACC8 +# define GET_IMM_MEM() \ + ldb 1(scratch1),ret0 ! \ + INC_KPC_2 +# else +# define GET_IMM_MEM() \ + ldb 2(scratch1),scratch2 ! \ + INC_KPC_3 ! \ + ldb 1(scratch1),ret0 ! \ + CYCLES_PLUS_1 ! \ + dep scratch2,23,8,ret0 +# endif +#else +# ifdef ACC8 +# define GET_IMM_MEM() \ + GET_1BYTE_ARG; \ + INC_KPC_2; +# else +# define GET_IMM_MEM() \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + INC_KPC_3; +# endif +#endif + + +#undef GET_ABS_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_ABS_RD() \ + ldb 2(scratch1),arg3 ! \ + INC_KPC_3 ! \ + ldb 1(scratch1),addr_latch ! \ + CYCLES_PLUS_2 ! \ + dep dbank,23,24,arg3 ! \ + ldwx,s arg3(page_info_ptr),scratch2 ! \ + copy addr_latch,scratch4 ! \ + dep arg3,23,24,addr_latch ! \ + ldbx scratch4(scratch2),ret0 ! \ + extru,= scratch2,BANK_IO_BIT,1,0 ! \ + bl get_memory_iocheck_stub_asm,link ! \ + copy addr_latch,arg0 +# else +# define GET_ABS_RD() \ + ldb 1(scratch1),arg0 ! \ + CYCLES_PLUS_1 ! \ + ldb 2(scratch1),scratch2 ! \ + INC_KPC_3 ! \ + dep dbank,15,16,arg0 ! \ + bl get_mem_long_16,link ! \ + dep scratch2,23,8,arg0 +# endif +#else +# ifdef ACC8 +# define GET_ABS_RD() \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + GET_MEMORY8((dbank << 16) + arg, arg); \ + INC_KPC_3; +# else +# define GET_ABS_RD() \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + GET_MEMORY16((dbank << 16) + arg, arg, 0); \ + INC_KPC_3; +# endif +#endif + + +#undef GET_LONG_RD + + +#ifdef ASM +# ifdef ACC8 +# define GET_LONG_RD() \ + ldb 1(scratch1),arg0 ! \ + INC_KPC_4 ! \ + ldb 2(scratch1),scratch2 ! \ + CYCLES_PLUS_2 ! \ + ldb 3(scratch1),scratch1 ! \ + dep scratch2,23,8,arg0 ! \ + bl get_mem_long_8,link ! \ + dep scratch1,15,8,arg0 +# else +# define GET_LONG_RD() \ + ldb 1(scratch1),arg0 ! \ + INC_KPC_4 ! \ + ldb 2(scratch1),scratch2 ! \ + CYCLES_PLUS_2 ! \ + ldb 3(scratch1),scratch1 ! \ + dep scratch2,23,8,arg0 ! \ + bl get_mem_long_16,link ! \ + dep scratch1,15,8,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define GET_LONG_RD() \ + GET_3BYTE_ARG; \ + CYCLES_PLUS_2; \ + GET_MEMORY8(arg, arg); \ + INC_KPC_4; +# else +# define GET_LONG_RD() \ + GET_3BYTE_ARG; \ + CYCLES_PLUS_2; \ + GET_MEMORY16(arg, arg, 0); \ + INC_KPC_4; +# endif +#endif + + + +#undef GET_DLOC_IND_Y_RD + +#undef GET_DLOC_IND_Y_WR_SPECIAL2 + +#define GET_DLOC_IND_Y_WR_SPECIAL2() \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_direct_page_16,link ! \ + extru arg0,31,16,arg0 ! \ + dep dbank,15,8,ret0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + add yreg,ret0,arg0 /* don't change this instr */ + /* or add any after */ + /* to preserve ret0 & arg0 */ + + +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_IND_Y_RD() \ + ldb 1(scratch1),arg0 ! \ + INC_KPC_2 ! \ + GET_DLOC_IND_Y_WR_SPECIAL2() ! \ + xor arg0,ret0,scratch1 ! \ + extru,= psr,27,1,0 ! \ + extru,= scratch1,23,8,0 ! \ + CYCLES_PLUS_1 ! \ + bl get_mem_long_8,link ! \ + nop +# else +# define GET_DLOC_IND_Y_RD() \ + ldb 1(scratch1),arg0 ! \ + INC_KPC_2 ! \ + GET_DLOC_IND_Y_WR_SPECIAL2() ! \ + xor arg0,ret0,scratch1 ! \ + extru,= psr,27,1,0 ! \ + extru,= scratch1,23,8,0 ! \ + CYCLES_PLUS_1 ! \ + bl get_mem_long_16,link ! \ + nop +# endif +#else /* C */ +# ifdef ACC8 +# define GET_DLOC_IND_Y_RD() \ + GET_1BYTE_ARG; \ + GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, tmp1); \ + tmp1 += (dbank << 16); \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + tmp2 = tmp1 + yreg; \ + if(((psr & 0x10) == 0) || ((tmp1 ^ tmp2) & 0xff00)) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + GET_MEMORY8(tmp2, arg); +# else +# define GET_DLOC_IND_Y_RD() \ + GET_1BYTE_ARG; \ + GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, tmp1); \ + tmp1 += (dbank << 16); \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + tmp2 = tmp1 + yreg; \ + if(((psr & 0x10) == 0) || ((tmp1 ^ tmp2) & 0xff00)) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + GET_MEMORY16(tmp2, arg, 0); +# endif +#endif + + +#undef GET_DLOC_IND_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_IND_RD() \ + ldb 1(scratch1),arg0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + INC_KPC_2 ! \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_direct_page_16,link ! \ + extru arg0,31,16,arg0 ! \ + copy ret0,arg0 ! \ + bl get_mem_long_8,link ! \ + dep dbank,15,16,arg0 +# else +# define GET_DLOC_IND_RD() \ + ldb 1(scratch1),arg0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + INC_KPC_2 ! \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_direct_page_16,link ! \ + extru arg0,31,16,arg0 ! \ + copy ret0,arg0 ! \ + bl get_mem_long_16,link ! \ + dep dbank,15,16,arg0 +# endif +#else +# ifdef ACC8 +# define GET_DLOC_IND_RD() \ + GET_1BYTE_ARG; \ + INC_KPC_2; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, arg); \ + GET_MEMORY8((dbank << 16) + arg, arg); +# else +# define GET_DLOC_IND_RD() \ + GET_1BYTE_ARG; \ + INC_KPC_2; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, arg); \ + GET_MEMORY16((dbank << 16) + arg, arg, 0); +# endif +#endif + + +#undef GET_DLOC_X_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_X_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_INDEX_WR_A(xreg) ! \ + bl get_mem_b0_8,link ! \ + GET_DLOC_INDEX_WR_B(xreg) +# else +# define GET_DLOC_X_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_INDEX_WR_A(xreg) ! \ + bl get_mem_b0_16,link ! \ + GET_DLOC_INDEX_WR_B(xreg) +# endif +#else +# ifdef ACC8 +# define GET_DLOC_X_RD() \ + GET_1BYTE_ARG; \ + CYCLES_PLUS_1; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + arg = (arg + xreg + direct) & 0xffff; \ + if(psr & 0x100) { \ + if((direct & 0xff) == 0) { \ + arg = (direct & 0xff00) | (arg & 0xff); \ + } \ + } \ + GET_MEMORY8(arg & 0xffff, arg); +# else +# define GET_DLOC_X_RD() \ + GET_1BYTE_ARG; \ + CYCLES_PLUS_1; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + arg = (arg + xreg + direct) & 0xffff; \ + if(psr & 0x100) { \ + if((direct & 0xff) == 0) { \ + arg = (direct & 0xff00) | (arg & 0xff); \ + } \ + } \ + GET_MEMORY16(arg, arg, 1); +# endif +#endif + + +#undef GET_DISP8_S_IND_Y_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DISP8_S_IND_Y_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DISP8_S_IND_Y_WR() ! \ + bl get_mem_long_8,link ! \ + nop +# else +# define GET_DISP8_S_IND_Y_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DISP8_S_IND_Y_WR() ! \ + bl get_mem_long_16,link ! \ + nop +# endif +#else +# ifdef ACC8 +# define GET_DISP8_S_IND_Y_RD() \ + GET_1BYTE_ARG; \ + GET_DISP8_S_IND_Y_WR(); \ + GET_MEMORY8(arg, arg); +# else +# define GET_DISP8_S_IND_Y_RD() \ + GET_1BYTE_ARG; \ + GET_DISP8_S_IND_Y_WR(); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + +#undef GET_DLOC_L_IND_Y_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_DLOC_L_IND_Y_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_L_IND_Y_WR() ! \ + bl get_mem_long_8,link ! \ + nop +# else +# define GET_DLOC_L_IND_Y_RD() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_L_IND_Y_WR() ! \ + bl get_mem_long_16,link ! \ + nop +# endif +#else /* C */ +# ifdef ACC8 +# define GET_DLOC_L_IND_Y_RD() \ + GET_1BYTE_ARG; \ + GET_DLOC_L_IND_Y_WR(); \ + GET_MEMORY8(arg, arg); +# else +# define GET_DLOC_L_IND_Y_RD() \ + GET_1BYTE_ARG; \ + GET_DLOC_L_IND_Y_WR(); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + +#undef GET_ABS_INDEX_ADDR_FOR_RD + +#ifdef ASM +/* to get cycle right: add 1 cycle */ +/* if (x is 16bit) || (carry into high byte), add another cycle */ +/* So, if x==16bit, add 1. If x==8bit then add 1 if carry */ +# define GET_ABS_INDEX_ADDR_FOR_RD(index_reg) \ + ldb 1(scratch1),ret0 ! \ + CYCLES_PLUS_1 ! \ + ldb 2(scratch1),scratch1 ! \ + dep dbank,15,16,ret0 ! \ + INC_KPC_3 ! \ + dep scratch1,23,8,ret0 ! \ + add ret0,index_reg,arg0 ! \ + xor arg0,ret0,scratch1 ! \ + extru,= psr,27,1,0 ! \ + extru,= scratch1,23,8,0 ! \ + CYCLES_PLUS_1 +#else /* C */ +# define GET_ABS_INDEX_ADDR_FOR_RD(index_reg) \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + INC_KPC_3; \ + tmp1 = (dbank << 16) + arg; \ + arg = tmp1 + index_reg; \ + if(((psr & 0x10) == 0) || ((tmp1 ^ arg) & 0xff00)) { \ + CYCLES_PLUS_1; \ + } +#endif + +#undef GET_ABS_Y_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_ABS_Y_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(yreg) ! \ + bl get_mem_long_8,link ! \ + extru arg0,31,24,arg0 +# else +# define GET_ABS_Y_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(yreg) ! \ + bl get_mem_long_16,link ! \ + extru arg0,31,24,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define GET_ABS_Y_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(yreg); \ + GET_MEMORY8(arg, arg); +# else +# define GET_ABS_Y_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(yreg); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + + + +#undef GET_ABS_X_RD +#undef GET_ABS_X_RD_WR + +#ifdef ASM +# ifdef ACC8 +# define GET_ABS_X_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(xreg) ! \ + bl get_mem_long_8,link ! \ + extru arg0,31,24,arg0 + +# define GET_ABS_X_RD_WR() \ + ldb 1(scratch1),ret0 ! \ + INC_KPC_3 ! \ + ldb 2(scratch1),scratch1 ! \ + dep dbank,15,16,ret0 ! \ + CYCLES_PLUS_2 ! \ + dep scratch1,23,8,ret0 ! \ + add ret0,xreg,arg0 ! \ + bl get_mem_long_8,link ! \ + extru arg0,31,24,arg0 +# else +# define GET_ABS_X_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(xreg) ! \ + bl get_mem_long_16,link ! \ + extru arg0,31,24,arg0 + +# define GET_ABS_X_RD_WR() \ + ldb 1(scratch1),ret0 ! \ + INC_KPC_3 ! \ + ldb 2(scratch1),scratch1 ! \ + dep dbank,15,16,ret0 ! \ + CYCLES_PLUS_2 ! \ + dep scratch1,23,8,ret0 ! \ + add ret0,xreg,arg0 ! \ + bl get_mem_long_16,link ! \ + extru arg0,31,24,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define GET_ABS_X_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(xreg); \ + GET_MEMORY8(arg, arg); + +# define GET_ABS_X_RD_WR() \ + GET_2BYTE_ARG; \ + INC_KPC_3; \ + CYCLES_PLUS_2; \ + arg = (dbank << 16) + ((arg + xreg) & 0xffff); \ + GET_MEMORY8(arg, arg); +# else +# define GET_ABS_X_RD() \ + GET_ABS_INDEX_ADDR_FOR_RD(xreg); \ + GET_MEMORY16(arg, arg, 0); + +# define GET_ABS_X_RD_WR() \ + GET_2BYTE_ARG; \ + INC_KPC_3; \ + CYCLES_PLUS_2; \ + arg = (dbank << 16) + ((arg + xreg) & 0xffff); \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + +#undef GET_LONG_X_RD + +#ifdef ASM +# ifdef ACC8 +# define GET_LONG_X_RD() \ + ldb 1(scratch1),ret0 ! \ + ldb 2(scratch1),scratch2 ! \ + CYCLES_PLUS_2 ! \ + ldb 3(scratch1),scratch1 ! \ + INC_KPC_4 ! \ + dep scratch2,23,8,ret0 ! \ + dep scratch1,15,8,ret0 ! \ + add ret0,xreg,arg0 ! \ + bl get_mem_long_8,link ! \ + extru arg0,31,24,arg0 +# else +# define GET_LONG_X_RD() \ + ldb 1(scratch1),ret0 ! \ + ldb 2(scratch1),scratch2 ! \ + CYCLES_PLUS_2 ! \ + ldb 3(scratch1),scratch1 ! \ + INC_KPC_4 ! \ + dep scratch2,23,8,ret0 ! \ + dep scratch1,15,8,ret0 ! \ + add ret0,xreg,arg0 ! \ + bl get_mem_long_16,link ! \ + extru arg0,31,24,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define GET_LONG_X_RD() \ + GET_3BYTE_ARG; \ + arg = (arg + xreg) & 0xffffff; \ + INC_KPC_4; \ + CYCLES_PLUS_2; \ + GET_MEMORY8(arg, arg); +# else +# define GET_LONG_X_RD() \ + GET_3BYTE_ARG; \ + arg = (arg + xreg) & 0xffffff; \ + INC_KPC_4; \ + CYCLES_PLUS_2; \ + GET_MEMORY16(arg, arg, 0); +# endif +#endif + + +#define SET_NEG_ZERO16(val) \ + zero = val; \ + neg = (val) >> 15; + +# define SET_NEG_ZERO8(val) \ + zero = val; \ + neg = (val) >> 7; + +#define SET_CARRY8(val) \ + psr = (psr & ~1) + (((val) >> 8) & 1); + +#define SET_CARRY16(val) \ + psr = (psr & ~1) + (((val) >> 16) & 1); + +#if 0 +# define NEGZERO8(val) SET_NEG_ZERO8(val) +#else +# define NEGZERO16(val) SET_NEG_ZERO16(val) +#endif + +#define SET_INDEX_REG(src, dest) \ + if(psr & 0x10) { \ + dest = (src) & 0xff; \ + SET_NEG_ZERO8(dest); \ + } else { \ + dest = (src) & 0xffff; \ + SET_NEG_ZERO16(dest); \ + } + +#define LD_INDEX_INST(index_reg, in_bank) \ + if(psr & 0x10) { \ + GET_MEMORY8(arg, arg); \ + } else { \ + GET_MEMORY16(arg, arg, in_bank);\ + } \ + SET_INDEX_REG(arg, index_reg); + +#define LDX_INST(in_bank) LD_INDEX_INST(xreg, in_bank) +#define LDY_INST(in_bank) LD_INDEX_INST(yreg, in_bank) + +#undef ORA_INST + +#ifdef ASM +# ifdef ACC8 +# define ORA_INST() \ + ldi 0xff,scratch1 ! \ + or acc,ret0,arg0 ! \ + and arg0,scratch1,zero ! \ + extru arg0,24,1,neg ! \ + b dispatch ! \ + dep arg0,31,8,acc +# else +# define ORA_INST() \ + zdepi -1,31,16,scratch1 ! \ + or acc,ret0,arg0 ! \ + and arg0,scratch1,zero ! \ + extru arg0,16,1,neg ! \ + b dispatch ! \ + dep arg0,31,16,acc +# endif +#else /* C */ +# ifdef ACC8 +# define ORA_INST() \ + tmp1 = (acc | arg) & 0xff; \ + acc = (acc & 0xff00) + tmp1; \ + SET_NEG_ZERO8(tmp1); +# else +# define ORA_INST() \ + acc = (acc | arg); \ + SET_NEG_ZERO16(acc); +# endif +#endif + +#undef AND_INST + +#ifdef ASM +# ifdef ACC8 +# define AND_INST() \ + ldi 0xff,scratch1 ! \ + and acc,ret0,arg0 ! \ + and arg0,scratch1,zero ! \ + extru arg0,24,1,neg ! \ + b dispatch ! \ + dep arg0,31,8,acc +# else +# define AND_INST() \ + zdepi -1,31,16,scratch1 ! \ + and acc,ret0,arg0 ! \ + and arg0,scratch1,zero ! \ + extru arg0,16,1,neg ! \ + b dispatch ! \ + dep arg0,31,16,acc +# endif +#else /* C */ +# ifdef ACC8 +# define AND_INST() \ + tmp1 = (acc & arg) & 0xff; \ + acc = (acc & 0xff00) + tmp1; \ + SET_NEG_ZERO8(tmp1); +# else +# define AND_INST() \ + acc = (acc & arg); \ + SET_NEG_ZERO16(acc); +# endif +#endif + +#undef EOR_INST + +#ifdef ASM +# ifdef ACC8 +# define EOR_INST() \ + ldi 0xff,scratch1 ! \ + xor acc,ret0,arg0 ! \ + and arg0,scratch1,zero ! \ + extru arg0,24,1,neg ! \ + b dispatch ! \ + dep arg0,31,8,acc +# else +# define EOR_INST() \ + zdepi -1,31,16,scratch1 ! \ + xor acc,ret0,arg0 ! \ + and arg0,scratch1,zero ! \ + extru arg0,16,1,neg ! \ + b dispatch ! \ + dep arg0,31,16,acc +# endif +#else /* C */ +# ifdef ACC8 +# define EOR_INST() \ + tmp1 = (acc ^ arg) & 0xff; \ + acc = (acc & 0xff00) + tmp1; \ + SET_NEG_ZERO8(tmp1); +# else +# define EOR_INST() \ + acc = (acc ^ arg); \ + SET_NEG_ZERO16(acc); +# endif +#endif + +# undef LDA_INST + +#ifdef ASM +# ifdef ACC8 +# define LDA_INST() \ + extru ret0,31,8,zero ! \ + extru ret0,24,1,neg ! \ + b dispatch ! \ + dep zero,31,8,acc +# else +# define LDA_INST() \ + extru ret0,31,16,zero ! \ + extru ret0,16,1,neg ! \ + b dispatch ! \ + dep zero,31,16,acc +# endif +#else /* C*/ +# ifdef ACC8 +# define LDA_INST() \ + acc = (acc & 0xff00) + (arg & 0xff); \ + SET_NEG_ZERO8(arg & 0xff); +# else +# define LDA_INST() \ + acc = (arg & 0xffff); \ + SET_NEG_ZERO16(acc); +# endif +#endif + +# undef ADC_INST + +#ifdef ASM +# ifdef ACC8 +# define ADC_INST() \ + b adc_binary_8 ! \ + extru acc,31,8,arg0 +# else +# define ADC_INST() \ + b adc_binary_16 ! \ + extru acc,31,16,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define ADC_INST() \ + tmp1 = do_adc_sbc8(acc & 0xff, arg & 0xff, psr, 0); \ + acc = (acc & 0xff00) + (tmp1 & 0xff); \ + psr = (tmp1 >> 16); \ + zero = !(psr & 0x2); \ + neg = (psr >> 7) & 1; +# else +# define ADC_INST() \ + tmp1 = do_adc_sbc16(acc, arg & 0xffff, psr, 0); \ + acc = (tmp1 & 0xffff); \ + psr = (tmp1 >> 16); \ + zero = !(psr & 0x2); \ + neg = (psr >> 7) & 1; +# endif +#endif + + +# undef SBC_INST + +#ifdef ASM +# ifdef ACC8 +# define SBC_INST() \ + uaddcm 0,ret0,ret0 ! \ + b sbc_binary_8 ! \ + extru acc,31,8,arg0 +# else +# define SBC_INST() \ + uaddcm 0,ret0,ret0 ! \ + b sbc_binary_16 ! \ + extru acc,31,16,arg0 +# endif +#else /* C */ +# ifdef ACC8 +# define SBC_INST() \ + tmp1 = do_adc_sbc8(acc & 0xff, arg & 0xff, psr, 1); \ + acc = (acc & 0xff00) + (tmp1 & 0xff); \ + psr = (tmp1 >> 16); \ + zero = !(psr & 0x2); \ + neg = (psr >> 7) & 1; +# else +# define SBC_INST() \ + tmp1 = do_adc_sbc16(acc, arg & 0xffff, psr, 1); \ + acc = (tmp1 & 0xffff); \ + psr = (tmp1 >> 16); \ + zero = !(psr & 0x2); \ + neg = (psr >> 7) & 1; +# endif +#endif + + +# undef CMP_INST + +#ifdef ASM +# ifdef ACC8 +# define CMP_INST() ! \ + extru acc,31,8,scratch1 ! \ + subi 0x100,ret0,ret0 ! \ + ldi 0xff,scratch2 ! \ + add ret0,scratch1,ret0 ! \ + extru ret0,23,1,scratch1 ! \ + and ret0,scratch2,zero ! \ + extru ret0,24,1,neg ! \ + b dispatch ! \ + dep scratch1,31,1,psr +# else +# define CMP_INST() ! \ + ldil l%0x10000,scratch3 ! \ + zdepi -1,31,16,scratch2 ! \ + sub scratch3,ret0,ret0 ! \ + add ret0,acc,ret0 ! \ + extru ret0,15,1,scratch1 ! \ + and ret0,scratch2,zero ! \ + extru ret0,16,1,neg ! \ + b dispatch ! \ + dep scratch1,31,1,psr +# endif +#else /* C */ +# ifdef ACC8 +# define CMP_INST() \ + arg = (acc & 0xff) + (0x100 - arg); \ + SET_CARRY8(arg); \ + arg = arg & 0xff; \ + SET_NEG_ZERO8(arg & 0xff); +# else +# define CMP_INST() \ + arg = (acc & 0xffff) + (0x10000 - arg); \ + SET_CARRY16(arg); \ + arg = arg & 0xffff; \ + SET_NEG_ZERO16(arg & 0xffff); +# endif +#endif + +# undef BIT_INST + +#ifdef ASM +# ifdef ACC8 +# define BIT_INST() \ + ldi 0xff,scratch1 ! \ + and acc,ret0,arg0 ! \ + extru ret0,24,1,neg ! \ + and arg0,scratch1,zero ! \ + extru ret0,25,1,scratch2 ! \ + b dispatch ! \ + dep scratch2,25,1,psr +# else +# define BIT_INST() \ + zdepi -1,31,16,scratch1 ! \ + and acc,ret0,arg0 ! \ + extru ret0,16,1,neg ! \ + and arg0,scratch1,zero ! \ + extru ret0,17,1,scratch2 ! \ + b dispatch ! \ + dep scratch2,25,1,psr +# endif +#else /* C */ +# ifdef ACC8 +# define BIT_INST() \ + neg = arg >> 7; \ + zero = (acc & arg & 0xff); \ + psr = (psr & (~0x40)) | (arg & 0x40); +# else +# define BIT_INST() \ + neg = arg >> 15; \ + zero = (acc & arg & 0xffff); \ + psr = (psr & (~0x40)) | ((arg >> 8) & 0x40); +# endif +#endif + +# undef STA_INST + +#ifdef ASM +# ifdef ACC8 +# define STA_INST() \ + extru acc,31,8,arg1 ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +# define STA_INST() \ + extru acc,31,16,arg1 ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C*/ +# ifdef ACC8 +# define STA_INST(in_bank) \ + SET_MEMORY8(arg, acc); +# else +# define STA_INST(in_bank) \ + SET_MEMORY16(arg, acc, in_bank); +# endif +#endif + + +#undef TSB_INST + +#ifdef ASM +# ifdef ACC8 +/* Uses addr_latch as full apple addr to write data to */ +# define TSB_INST() \ + or acc,ret0,arg1 ! \ + CYCLES_PLUS_1 ! \ + extru arg1,31,8,arg1 ! \ + and ret0,acc,zero ! \ + copy addr_latch,arg0 ! \ + extru zero,31,8,zero ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +/* Uses addr_latch as full apple addr to write data to */ +# define TSB_INST() \ + or acc,ret0,arg1 ! \ + CYCLES_PLUS_1 ! \ + extru arg1,31,16,arg1 ! \ + and ret0,acc,zero ! \ + copy addr_latch,arg0 ! \ + extru zero,31,16,zero ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C*/ +# ifdef ACC8 +# define TSB_INST(in_bank) \ + tmp1 = arg | acc; \ + CYCLES_PLUS_1; \ + zero = arg & acc; \ + SET_MEMORY8(addr_latch, tmp1); +# else +# define TSB_INST(in_bank) \ + tmp1 = arg | acc; \ + CYCLES_PLUS_1; \ + zero = arg & acc; \ + SET_MEMORY16(addr_latch, tmp1, in_bank); +# endif +#endif + + +#undef ASL_INST + +#ifdef ASM +# ifdef ACC8 +/* Uses addr_latch as full apple addr to write data to */ +# define ASL_INST() \ + ldi 0xff,scratch1 ! \ + copy addr_latch,arg0 ! \ + sh1add ret0,0,scratch3 ! \ + CYCLES_PLUS_1 ! \ + extru scratch3,24,1,neg ! \ + and scratch3,scratch1,zero ! \ + extru scratch3,23,1,scratch2 ! \ + copy zero,arg1 ! \ + dep scratch2,31,1,psr /* set carry */ ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +/* Uses addr_latch as full apple addr to write data to */ +# define ASL_INST() \ + zdepi -1,31,16,scratch1 ! \ + copy addr_latch,arg0 ! \ + sh1add ret0,0,scratch3 ! \ + CYCLES_PLUS_1 ! \ + extru scratch3,16,1,neg ! \ + and scratch3,scratch1,zero ! \ + extru scratch3,15,1,scratch2 ! \ + copy zero,arg1 ! \ + dep scratch2,31,1,psr /* set carry */ ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define ASL_INST(in_bank) \ + psr = (psr & 0x1fe) + ((arg >> 7) & 1); \ + tmp1 = (arg << 1) & 0xff; \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO8(tmp1); \ + SET_MEMORY8(addr_latch, tmp1); +# else +# define ASL_INST(in_bank) \ + psr = (psr & 0x1fe) + ((arg >> 15) & 1);\ + tmp1 = (arg << 1) & 0xffff; \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO16(tmp1); \ + SET_MEMORY16(addr_latch, tmp1, in_bank); +# endif +#endif + +# undef ROL_INST + +#ifdef ASM +# ifdef ACC8 +/* Uses addr_latch as full apple addr to write data to */ +# define ROL_INST() \ + extru psr,31,1,scratch2 ! \ + ldi 0xff,scratch1 ! \ + copy addr_latch,arg0 ! \ + sh1add ret0,scratch2,scratch3 ! \ + CYCLES_PLUS_1 ! \ + extru scratch3,24,1,neg ! \ + and scratch3,scratch1,zero ! \ + extru scratch3,23,1,scratch2 ! \ + copy zero,arg1 ! \ + dep scratch2,31,1,psr /* set carry */ ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +/* Uses addr_latch as full apple addr to write data to */ +# define ROL_INST() \ + extru psr,31,1,scratch2 ! \ + copy addr_latch,arg0 ! \ + zdepi -1,31,16,scratch1 ! \ + sh1add ret0,scratch2,scratch3 ! \ + CYCLES_PLUS_1 ! \ + extru scratch3,16,1,neg ! \ + and scratch3,scratch1,zero ! \ + extru scratch3,15,1,scratch2 ! \ + copy zero,arg1 ! \ + dep scratch2,31,1,psr /* set carry */ ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define ROL_INST(in_bank) \ + arg = (arg << 1) | (psr & 1); \ + SET_MEMORY8(addr_latch, arg); \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO8(arg & 0xff); \ + SET_CARRY8(arg); +# else +# define ROL_INST(in_bank) \ + arg = (arg << 1) | (psr & 1); \ + SET_MEMORY16(addr_latch, arg, in_bank); \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO16(arg & 0xffff); \ + SET_CARRY16(arg); +# endif +#endif + +# undef LSR_INST + +#ifdef ASM +# ifdef ACC8 +/* Uses addr_latch as full apple addr to write data to */ +# define LSR_INST() \ + copy addr_latch,arg0 ! \ + extru ret0,30,7,zero ! \ + CYCLES_PLUS_1 ! \ + ldi 0,neg ! \ + dep ret0,31,1,psr /* set carry */ ! \ + copy zero,arg1 ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +/* Uses addr_latch as full apple addr to write data to */ +# define LSR_INST() \ + copy addr_latch,arg0 ! \ + extru ret0,30,15,zero ! \ + CYCLES_PLUS_1 ! \ + ldi 0,neg ! \ + dep ret0,31,1,psr /* set carry */ ! \ + copy zero,arg1 ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define LSR_INST(in_bank) \ + SET_CARRY8(arg << 8); \ + arg = (arg >> 1) & 0x7f; \ + SET_MEMORY8(addr_latch, arg); \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO8(arg); +# else +# define LSR_INST(in_bank) \ + SET_CARRY16(arg << 16); \ + arg = (arg >> 1) & 0x7fff; \ + SET_MEMORY16(addr_latch, arg, in_bank); \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO16(arg); +# endif +#endif + + +# undef ROR_INST + +#ifdef ASM +# ifdef ACC8 +# define ROR_INST() ! \ + extru psr,31,1,neg ! \ + copy addr_latch,arg0 ! \ + extru ret0,30,7,zero ! \ + CYCLES_PLUS_1 ! \ + dep neg,24,1,zero ! \ + copy zero,arg1 ! \ + dep ret0,31,1,psr ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +# define ROR_INST() ! \ + extru psr,31,1,neg ! \ + copy addr_latch,arg0 ! \ + extru ret0,30,15,zero ! \ + CYCLES_PLUS_1 ! \ + dep neg,16,1,zero ! \ + copy zero,arg1 ! \ + dep ret0,31,1,psr ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define ROR_INST(in_bank) \ + tmp1 = psr & 1; \ + SET_CARRY8(arg << 8); \ + arg = ((arg >> 1) & 0x7f) | (tmp1 << 7); \ + SET_MEMORY8(addr_latch, arg); \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO8(arg); +# else +# define ROR_INST(in_bank) \ + tmp1 = psr & 1; \ + SET_CARRY16(arg << 16); \ + arg = ((arg >> 1) & 0x7fff) | (tmp1 << 15); \ + SET_MEMORY16(addr_latch, arg, in_bank); \ + CYCLES_PLUS_1; \ + SET_NEG_ZERO16(arg); +# endif +#endif + +# undef TRB_INST + +#ifdef ASM +# ifdef ACC8 +/* Uses addr_latch as full apple addr to write data to */ +# define TRB_INST() \ + andcm ret0,acc,arg1 ! \ + copy addr_latch,arg0 ! \ + and ret0,acc,zero ! \ + extru arg1,31,8,arg1 ! \ + CYCLES_PLUS_1 ! \ + extru zero,31,8,zero ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +/* Uses addr_latch as full apple addr to write data to */ +# define TRB_INST() \ + andcm ret0,acc,arg1 ! \ + CYCLES_PLUS_1 ! \ + extru arg1,31,16,arg1 ! \ + and ret0,acc,zero ! \ + copy addr_latch,arg0 ! \ + extru zero,31,16,zero ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define TRB_INST(in_bank) \ + arg = arg & 0xff; \ + tmp1 = arg & ~acc; \ + CYCLES_PLUS_1; \ + zero = arg & acc; \ + SET_MEMORY8(addr_latch, tmp1); +# else +# define TRB_INST(in_bank) \ + tmp1 = arg & ~acc; \ + CYCLES_PLUS_1; \ + zero = arg & acc; \ + SET_MEMORY16(addr_latch, tmp1, in_bank); +# endif +#endif + +# undef DEC_INST + +#ifdef ASM +# ifdef ACC8 +# define DEC_INST() ! \ + addi -1,ret0,ret0 ! \ + copy addr_latch,arg0 ! \ + extru ret0,24,1,neg ! \ + CYCLES_PLUS_1 ! \ + extru ret0,31,8,zero ! \ + ldil l%dispatch,link ! \ + copy zero,arg1 ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +# define DEC_INST() ! \ + addi -1,ret0,ret0 ! \ + copy addr_latch,arg0 ! \ + extru ret0,16,1,neg ! \ + CYCLES_PLUS_1 ! \ + extru ret0,31,16,zero ! \ + ldil l%dispatch,link ! \ + copy zero,arg1 ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define DEC_INST(in_bank) \ + CYCLES_PLUS_1; \ + arg = (arg - 1) & 0xff; \ + SET_MEMORY8(addr_latch, arg); \ + SET_NEG_ZERO8(arg); +# else +# define DEC_INST(in_bank) \ + CYCLES_PLUS_1; \ + arg = (arg - 1) & 0xffff; \ + SET_MEMORY16(addr_latch, arg, in_bank); \ + SET_NEG_ZERO16(arg); +# endif +#endif + + +# undef INC_INST + +#ifdef ASM +# ifdef ACC8 +# define INC_INST() ! \ + addi 1,ret0,ret0 ! \ + copy addr_latch,arg0 ! \ + extru ret0,24,1,neg ! \ + CYCLES_PLUS_1 ! \ + extru ret0,31,8,zero ! \ + ldil l%dispatch,link ! \ + copy zero,arg1 ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +# define INC_INST() ! \ + addi 1,ret0,ret0 ! \ + copy addr_latch,arg0 ! \ + extru ret0,16,1,neg ! \ + CYCLES_PLUS_1 ! \ + extru ret0,31,16,zero ! \ + ldil l%dispatch,link ! \ + copy zero,arg1 ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define INC_INST(in_bank) \ + CYCLES_PLUS_1; \ + arg = (arg + 1) & 0xff; \ + SET_MEMORY8(addr_latch, arg); \ + SET_NEG_ZERO8(arg); +# else +# define INC_INST(in_bank) \ + CYCLES_PLUS_1; \ + arg = (arg + 1) & 0xffff; \ + SET_MEMORY16(addr_latch, arg, in_bank); \ + SET_NEG_ZERO16(arg); +# endif +#endif + +# undef STZ_INST + +#ifdef ASM +# ifdef ACC8 +# define STZ_INST() \ + ldi 0,arg1 ! \ + ldil l%dispatch,link ! \ + b set_mem_long_8 ! \ + ldo r%dispatch(link),link +# else +# define STZ_INST() \ + ldi 0,arg1 ! \ + ldil l%dispatch,link ! \ + b set_mem_long_16 ! \ + ldo r%dispatch(link),link +# endif +#else /* C */ +# ifdef ACC8 +# define STZ_INST(in_bank) \ + SET_MEMORY8(arg, 0); +# else +# define STZ_INST(in_bank) \ + SET_MEMORY16(arg, 0, in_bank); +# endif +#endif + + +#undef COND_BR1 +#undef COND_BR2 +#undef COND_BR_UNTAKEN + +#ifdef ASM +# define COND_BR1 \ + ldb 1(scratch1),arg0 + +/* be careful about modifying kpc as first instr of COND_Br2 since it */ +/* is in the delay slot of a branch! */ +# define COND_BR2 \ + addi 2,kpc,scratch3 ! \ + ldi 0x100,scratch4 ! \ + extrs arg0,31,8,ret0 ! \ + and scratch4,psr,scratch4 ! \ + add scratch3,ret0,ret0 ! \ + CYCLES_PLUS_1 ! \ + xor scratch3,ret0,scratch3 ! \ + and,= scratch4,scratch3,0 ! \ + CYCLES_PLUS_1 ! \ + b dispatch ! \ + dep ret0,31,16,kpc + + +# define COND_BR_UNTAKEN \ + b dispatch ! \ + INC_KPC_2 +#else /* C */ +# define BRANCH_DISP8(cond) \ + GET_1BYTE_ARG; \ + tmp2 = kpc & 0xff0000; \ + kpc += 2; \ + tmp1 = kpc; \ + if(cond) { \ + kpc = kpc + arg - ((arg & 0x80) << 1); \ + CYCLES_PLUS_1; \ + if((tmp1 ^ kpc) & psr & 0x100) { \ + CYCLES_PLUS_1; \ + } \ + } \ + kpc = tmp2 + (kpc & 0xffff); +#endif + +#undef STY_INST +#undef STX_INST + +#ifdef ASM +# define STY_INST() \ + ldil l%dispatch,link ! \ + b set_mem_yreg ! \ + ldo r%dispatch(link),link + +# define STX_INST() \ + ldil l%dispatch,link ! \ + b set_mem_xreg ! \ + ldo r%dispatch(link),link +#else /* C */ +# define STY_INST(in_bank) \ + if(psr & 0x10) { \ + SET_MEMORY8(arg, yreg); \ + } else { \ + SET_MEMORY16(arg, yreg, in_bank);\ + } +# define STX_INST(in_bank) \ + if(psr & 0x10) { \ + SET_MEMORY8(arg, xreg); \ + } else { \ + SET_MEMORY16(arg, xreg, in_bank);\ + } +#endif + +#ifndef ASM + +# define C_LDX_ABS_Y() \ + GET_ABS_INDEX_ADDR_FOR_RD(yreg); \ + LDX_INST(0); + +# define C_LDY_ABS_X() \ + GET_ABS_INDEX_ADDR_FOR_RD(xreg); \ + LDY_INST(0); + +# define C_LDX_ABS() \ + GET_ABS_ADDR(); \ + LDX_INST(0); + +# define C_LDY_ABS() \ + GET_ABS_ADDR(); \ + LDY_INST(0); + +# define C_LDX_DLOC() \ + GET_DLOC_ADDR(); \ + LDX_INST(1); + +# define C_LDY_DLOC() \ + GET_DLOC_ADDR(); \ + LDY_INST(1); + +# define C_LDY_DLOC_X() \ + GET_DLOC_X_ADDR(); \ + LDY_INST(1); + +# define C_LDX_DLOC_Y() \ + GET_DLOC_Y_ADDR(); \ + LDX_INST(1); + +# define CP_INDEX_VAL(index_reg) \ + arg = 0x100 - arg + index_reg; \ + if((psr & 0x10) == 0) { \ + arg += 0xff00; \ + SET_NEG_ZERO16(arg & 0xffff); \ + SET_CARRY16(arg); \ + } else { \ + SET_NEG_ZERO8(arg & 0xff);\ + SET_CARRY8(arg); \ + } + +# define CP_INDEX_LOAD(index_reg, in_bank) \ + if((psr & 0x10) != 0) { \ + GET_MEMORY8(arg, arg); \ + } else { \ + GET_MEMORY16(arg, arg, in_bank);\ + } \ + CP_INDEX_VAL(index_reg) + +# define CPX_INST(in_bank) \ + CP_INDEX_LOAD(xreg, in_bank); + +# define CPY_INST(in_bank) \ + CP_INDEX_LOAD(yreg, in_bank); + +# define C_CPX_IMM() \ + INC_KPC_2; \ + if((psr & 0x10) == 0) { \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + INC_KPC_1; \ + } else { \ + GET_1BYTE_ARG; \ + } \ + CP_INDEX_VAL(xreg); + +# define C_CPY_IMM() \ + INC_KPC_2; \ + if((psr & 0x10) == 0) { \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + INC_KPC_1; \ + } else { \ + GET_1BYTE_ARG; \ + } \ + CP_INDEX_VAL(yreg); + +# define C_CPX_DLOC() \ + GET_DLOC_ADDR(); \ + CPX_INST(1); + +# define C_CPY_DLOC() \ + GET_DLOC_ADDR(); \ + CPY_INST(1); + +# define C_CPX_ABS() \ + GET_ABS_ADDR(); \ + CPX_INST(0); + +# define C_CPY_ABS() \ + GET_ABS_ADDR(); \ + CPY_INST(0); + +#endif + + + + +/* This is here to make sure all the macros expand to no instrs */ +/* if defs_instr_end_8 - start != 0, then something did expand */ + +#ifdef ASM +# ifdef ACC8 + .export defs_instr_end_8,data +defs_instr_end_8 .word 0 +# else + .export defs_instr_end_16,data +defs_instr_end_16 .word 0 +# endif +#endif diff --git a/src/dis.c b/src/dis.c new file mode 100644 index 0000000..352f135 --- /dev/null +++ b/src/dis.c @@ -0,0 +1,1342 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_dis_c[] = "@(#)$KmKId: dis.c,v 1.90 2003-11-18 17:35:30-05 kentd Exp $"; + +#include +#include "defc.h" +#include + +#include "disas.h" + +#define LINE_SIZE 160 + +extern byte *g_memory_ptr; +extern byte *g_slow_memory_ptr; +extern byte *g_rom_fc_ff_ptr; +extern byte *g_rom_cards_ptr; +extern word32 g_mem_size_base, g_mem_size_exp; +extern int halt_sim; +extern int enter_debug; +extern int statereg; +extern word32 stop_run_at; +extern int stop_on_c03x; +extern int Verbose; +extern int Halt_on; +extern int g_rom_version; + +extern int g_testing_enabled; + +int g_num_breakpoints = 0; +word32 g_breakpts[MAX_BREAK_POINTS]; + +extern int g_irq_pending; + +extern Engine_reg engine; + +#define W_BUF_LEN 128 +char w_buff[W_BUF_LEN]; + +int g_stepping = 0; + +word32 list_kpc; +int hex_line_len; +word32 a1,a2,a3,a4; +int a1bank, a2bank, a3bank, a4bank; +char *line_ptr; +int mode,old_mode; +int got_num; + +int g_quit_sim_now = 0; + +int +get_num() +{ + int tmp1; + + a2 = 0; + got_num = 0; + while(1) { + if(mode == 0 && got_num != 0) { +/* + printf("In getnum, mode =0, setting a1,a3 = a2\n"); + printf("a2: %x\n", a2); +*/ + a3 = a2; + a3bank = a2bank; + a1 = a2; + a1bank = a2bank; + } + tmp1 = *line_ptr++ & 0x7f; + if(tmp1 >= '0' && tmp1 <= '9') { + a2 = (a2 << 4) + tmp1 - '0'; + got_num = 1; + continue; + } + if(tmp1 >= 'a' && tmp1 <= 'f') { + a2 = (a2 << 4) + tmp1 - 'a' + 10; + got_num = 1; + continue; + } + if(tmp1 == '/') { + a2bank = a2; + a2 = 0; + continue; + } + return tmp1; + } +} + +void +debugger_help() +{ + printf("KEGS Debugger help (courtesy Fredric Devernay\n"); + printf("General command syntax: [bank]/[address][command]\n"); + printf("e.g. 'e1/0010B' to set a breakpoint at the interrupt jump pt\n"); + printf("Enter all addresses using lower-case\n"); + printf("As with the IIgs monitor, you can omit the bank number after\n"); + printf("having set it: 'e1/0010B' followed by '14B' will set\n"); + printf("breakpoints at e1/0010 and e1/0014\n"); + printf("\n"); + printf("g Go\n"); + printf("[bank]/[addr]g Go from [bank]/[address]\n"); + printf("s Step one instruction\n"); + printf("[bank]/[addr]s Step one instr at [bank]/[address]\n"); + printf("[bank]/[addr]B Set breakpoint at [bank]/[address]\n"); + printf("B Show all breakpoints\n"); + printf("[bank]/[addr]D Delete breakpoint at [bank]/[address]\n"); + printf("[bank]/[addr1].[addr2] View memory\n"); + printf("[bank]/[addr]L Disassemble memory\n"); + + printf("P Dump the trace to 'pc_log_out'\n"); + printf("Z Dump SCC state\n"); + printf("I Dump IWM state\n"); + printf("[drive].[track]I Dump IWM state\n"); + printf("E Dump Ensoniq state\n"); + printf("[osc]E Dump oscillator [osc] state\n"); + printf("R Dump dtime array and events\n"); + printf("T Show toolbox log\n"); + printf("[bank]/[addr]T Dump tools using ptr [bank]/[addr]\n"); + printf(" as 'tool_set_info'\n"); + printf("[mode]V XOR verbose with 1=DISK, 2=IRQ,\n"); + printf(" 4=CLK,8=SHADOW,10=IWM,20=DOC,\n"); + printf(" 40=ABD,80=SCC, 100=TEST, 200=VIDEO\n"); + printf("[mode]H XOR halt_on with 1=SCAN_INT,\n"); + printf(" 2=IRQ, 4=SHADOW_REG, 8=C70D_WRITES\n"); + printf("r Reset\n"); + printf("[0/1]=m Changes m bit for l listings\n"); + printf("[0/1]=x Changes x bit for l listings\n"); + printf("[t]=z Stops at absolute time t (obsolete)\n"); + printf("S show_bankptr_bank0 & smartport errs\n"); + printf("P show_pmhz\n"); + printf("A show_a2_line_stuff show_adb_log\n"); + printf("Ctrl-e Dump registers\n"); + printf("[bank]/[addr1].[addr2]us[file] Save mem area to [file]\n"); + printf("[bank]/[addr1].[addr2]ul[file] Load mem area from [file]\n"); + printf("v Show video information\n"); + printf("q Exit Debugger (and KEGS)\n"); +} + +void +do_debug_intfc() +{ + char linebuf[LINE_SIZE]; + int slot_drive; + int track; + int osc; + int done; + int ret_val; + + hex_line_len = 0x10; + a1 = 0; a2 = 0; a3 = 0; a4 = 0; + a1bank = 0; a2bank = 0; a3bank = 0; a4bank = 0; + list_kpc = engine.kpc; + g_stepping = 0; + mode = 0; old_mode = 0; + done = 0; + stop_run_at = -1; + + x_auto_repeat_on(0); + + if(g_quit_sim_now) { + printf("Exiting immediately\n"); + return; + } + + printf("Type 'h' for help\n"); + + while(!done) { + printf("> "); fflush(stdout); + if(read_line(linebuf,LINE_SIZE-1) <= 0) { + done = 1; + continue; + } + line_ptr = linebuf; + +/* + printf("input line: :%s:\n", linebuf); + printf("mode: %d\n", mode); +*/ + mode = 0; + + while(*line_ptr != 0) { + ret_val = get_num(); +/* + printf("ret_val: %x, got_num= %d\n", ret_val, + got_num); +*/ + old_mode = mode; + mode = 0; + switch(ret_val) { + case 'h': + debugger_help(); + break; + case 'R': + show_dtime_array(); + show_all_events(); + break; + case 'I': + slot_drive = -1; + track = -1; + if(got_num) { + if(old_mode == '.') { + slot_drive = a1; + } + track = a2; + } + iwm_show_track(slot_drive, track); + iwm_show_stats(); + break; + case 'E': + osc = -1; + if(got_num) { + osc = a2; + } + doc_show_ensoniq_state(osc); + break; + case 'T': + if(got_num) { + show_toolset_tables(a2bank, a2); + } else { + show_toolbox_log(); + } + break; + case 'v': + video_show_debug_info(); + break; + case 'V': + printf("g_irq_pending: %d\n", g_irq_pending); + printf("Setting Verbose ^= %04x\n", a1); + Verbose ^= a1; + printf("Verbose is now: %04x\n", Verbose); + break; + case 'H': + printf("Setting Halt_on ^= %04x\n", a1); + Halt_on ^= a1; + printf("Halt_on is now: %04x\n", Halt_on); + break; + case 'r': + do_reset(); + list_kpc = engine.kpc; + break; + case 'm': + if(old_mode == '=') { + if(!a1) { + engine.psr &= ~0x20; + } else { + engine.psr |= 0x20; + } + if(engine.psr & 0x100) { + engine.psr |= 0x30; + } + } + break; + case 'x': + if(old_mode == '=') { + if(!a1) { + engine.psr &= ~0x10; + } else { + engine.psr |= 0x10; + } + if(engine.psr & 0x100) { + engine.psr |= 0x30; + } + } + break; + case 'z': + if(old_mode == '=') { + stop_run_at = a1; + printf("Calling add_event for t:%08x\n", + a1); + add_event_stop((double)a1); + printf("set stop_run_at = %x\n", a1); + } + break; + case 'l': case 'L': + do_debug_list(); + break; + case 'Z': + show_scc_log(); + show_scc_state(); + break; + case 'S': + show_bankptrs_bank0rdwr(); + smartport_error(); + break; + case 'C': + show_xcolor_array(); + break; + case 'P': + show_pc_log(); + break; + case 'M': + show_pmhz(); + break; + case 'A': + show_a2_line_stuff(); + show_adb_log(); + break; + case 's': + g_stepping = 1; + if(got_num) { + engine.kpc = (a2bank<<16) + (a2&0xffff); + } + mode = 's'; + list_kpc = engine.kpc; + break; + case 'B': + if(got_num) { + printf("got_num: %d, a2bank: %x, a2: %x\n", got_num, a2bank, a2); + set_bp((a2bank << 16) + a2); + } else { + show_bp(); + } + break; + case 'D': + if(got_num) { + printf("got_num: %d, a2bank: %x, a2: %x\n", got_num, a2bank, a2); + delete_bp((a2bank << 16) + a2); + } + break; + case 'g': + case 'G': + printf("Going..\n"); + g_stepping = 0; + if(got_num) { + engine.kpc = (a2bank<<16) + (a2&0xffff); + } + if(ret_val == 'G' && g_testing_enabled) { + do_gen_test(got_num, a2); + } else { + do_go(); + } + list_kpc = engine.kpc; + break; + case 'q': + case 'Q': + printf("Exiting debugger\n"); + return; + break; + case 'u': + printf("Unix commands\n"); + do_debug_unix(); + break; + case ':': case '.': + case '+': case '-': + case '=': case ',': + mode = ret_val; + printf("Setting mode = %x\n", mode); + break; + case ' ': case '\t': + if(!got_num) { + mode = old_mode; + break; + } + do_blank(); + break; + case 0x05: /* ctrl-e */ + show_regs(); + break; + case '\n': + *line_ptr = 0; + if(old_mode == 's') { + do_blank(); + break; + } + if(line_ptr == &linebuf[1]) { + a2 = a1 | (hex_line_len - 1); + show_hex_mem(a1bank,a1,a2bank,a2, -1); + a1 = a2 + 1; + } else { + if(got_num == 1 || mode == 's') { + do_blank(); + } + } + break; + case 'w': + read_line(w_buff, W_BUF_LEN); + break; + case 'X': + stop_on_c03x = !stop_on_c03x; + printf("stop_on_c03x set to %d\n",stop_on_c03x); + break; + default: + printf("\nUnrecognized command: %s\n",linebuf); + *line_ptr = 0; + break; + } + } + + } + printf("Console closed.\n"); +} + +word32 +dis_get_memory_ptr(word32 addr) +{ + word32 tmp1, tmp2, tmp3; + + tmp1 = get_memory_c(addr, 0); + tmp2 = get_memory_c(addr + 1, 0); + tmp3 = get_memory_c(addr + 2, 0); + + return (tmp3 << 16) + (tmp2 << 8) + tmp1; +} + +void +show_one_toolset(FILE *toolfile, int toolnum, word32 addr) +{ + word32 rout_addr; + int num_routs; + int i; + + num_routs = dis_get_memory_ptr(addr); + fprintf(toolfile, "Tool 0x%02x, table: 0x%06x, num_routs:%03x\n", + toolnum, addr, num_routs); + + for(i = 1; i < num_routs; i++) { + rout_addr = dis_get_memory_ptr(addr + 4*i); + fprintf(toolfile, "%06x = %02x%02x\n", rout_addr, i, toolnum); + } +} + +void +show_toolset_tables(word32 a2bank, word32 addr) +{ + FILE *toolfile; + word32 tool_addr; + int num_tools; + int i; + + addr = (a2bank << 16) + (addr & 0xffff); + + toolfile = fopen("tool_set_info", "wt"); + if(toolfile == 0) { + fprintf(stderr, "fopen of tool_set_info failed: %d\n", errno); + exit(2); + } + + num_tools = dis_get_memory_ptr(addr); + fprintf(toolfile, "There are 0x%02x tools using ptr at %06x\n", + num_tools, addr); + + for(i = 1; i < num_tools; i++) { + tool_addr = dis_get_memory_ptr(addr + 4*i); + show_one_toolset(toolfile, i, tool_addr); + } + + fclose(toolfile); +} + + +#ifndef TEST65 +void +do_gen_test(int got_num, int base_seed) +{ + /* dummy */ +} +#endif + +void +set_bp(word32 addr) +{ + int count; + + printf("About to set BP at %06x\n", addr); + count = g_num_breakpoints; + if(count >= MAX_BREAK_POINTS) { + printf("Too many (0x%02x) breakpoints set!\n", count); + return; + } + + g_breakpts[count] = addr; + g_num_breakpoints = count + 1; + fixup_brks(); +} + +void +show_bp() +{ + int i; + + printf("Showing breakpoints set\n"); + for(i = 0; i < g_num_breakpoints; i++) { + printf("bp:%02x: %06x\n", i, g_breakpts[i]); + } +} + +void +delete_bp(word32 addr) +{ + int count; + int hit; + int i; + + printf("About to delete BP at %06x\n", addr); + count = g_num_breakpoints; + + hit = -1; + for(i = 0; i < count; i++) { + if(g_breakpts[i] == addr) { + hit = i; + break; + } + } + + if(hit < 0) { + printf("Breakpoint not found!\n"); + } else { + printf("Deleting brkpoint #0x%02x\n", hit); + for(i = hit+1; i < count; i++) { + g_breakpts[i-1] = g_breakpts[i]; + } + g_num_breakpoints = count - 1; + setup_pageinfo(); + } + + show_bp(); +} + +void +do_blank() +{ + int tmp, i; + + switch(old_mode) { + case 's': + tmp = a2; + if(tmp == 0) tmp = 1; + enter_debug = 0; + for(i = 0; i < tmp; i++) { + g_stepping = 1; + do_step(); + if(enter_debug || halt_sim != 0) { + if(halt_sim != HALT_EVENT) { + break; + } + } + } + list_kpc = engine.kpc; + /* video_update_through_line(262); */ + break; + case ':': + set_memory_c(((a3bank << 16) + a3), a2, 0); + a3++; + mode = old_mode; + break; + case '.': + case 0: + xam_mem(-1); + break; + case ',': + xam_mem(16); + break; + case '+': + printf("%x\n", a1 + a2); + break; + case '-': + printf("%x\n", a1 - a2); + break; + default: + printf("Unknown mode at space: %d\n", old_mode); + break; + } +} + +void +do_go() +{ + clear_halt(); + + run_prog(); + show_regs(); +} + +void +do_step() +{ + int size; + int size_mem_imm, size_x_imm; + + clear_halt(); + + run_prog(); + + show_regs(); + size_mem_imm = 2; + if(engine.psr & 0x20) { + size_mem_imm = 1; + } + size_x_imm = 2; + if(engine.psr & 0x10) { + size_x_imm = 1; + } + size = do_dis(stdout, engine.kpc, size_mem_imm, size_x_imm, 0, 0); +} + +void +xam_mem(int count) +{ + show_hex_mem(a1bank, a1, a2bank, a2, count); + a1 = a2 + 1; +} + +void +show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count) +{ + char ascii[MAXNUM_HEX_PER_LINE]; + word32 i; + int val, offset; + + if(count < 0) { + count = 16 - (start & 0xf); + } + + offset = 0; + ascii[0] = 0; + printf("Showing hex mem: bank: %x, start: %x, end: %x\n", + startbank, start, end); + for(i = start; i <= end; i++) { + if( (i==start) || (count == 16) ) { + printf("%04x:",i); + } + printf(" %02x", get_memory_c((startbank <<16) + i, 0)); + val = get_memory_c((startbank << 16) + i, 0) & 0x7f; + if(val < 32 || val >= 0x7f) { + val = '.'; + } + ascii[offset++] = val; + ascii[offset] = 0; + count--; + if(count <= 0) { + printf(" %s\n", ascii); + offset = 0; + ascii[0] = 0; + count = 16; + } + } + if(offset > 0) { + printf(" %s\n", ascii); + } +} + + +int +read_line(char *buf, int len) +{ + int space_left; + int ret; + + space_left = len; + + ret = 0; + buf[0] = 0; + while(space_left > 0) { + ret = read(0,buf,1); + if(ret <= 0) { + printf("read <= 0\n"); + return(len-space_left); + } + space_left -= ret; + if(buf[ret-1] == 0x0a) { + return(len-space_left); + } + buf = &buf[ret]; + } + return(len-space_left); +} + +void +do_debug_list() +{ + int i; + int size; + int size_mem_imm, size_x_imm; + + if(got_num) { + list_kpc = (a2bank << 16) + (a2 & 0xffff); + } + printf("%d=m %d=x %d=LCBANK\n", (engine.psr >> 5)&1, + (engine.psr >> 4) & 1, (statereg & 0x4) >> 2); + + size_mem_imm = 2; + if(engine.psr & 0x20) { + size_mem_imm = 1; + } + size_x_imm = 2; + if(engine.psr & 0x10) { + size_x_imm = 1; + } + for(i=0;i<20;i++) { + size = do_dis(stdout, list_kpc, size_mem_imm, + size_x_imm, 0, 0); + list_kpc += size; + } +} + +const char *g_kegs_rom_names[] = { "ROM", "ROM.01", "ROM.03", 0 }; + +const char *g_kegs_c1rom_names[] = { 0 }; +const char *g_kegs_c2rom_names[] = { 0 }; +const char *g_kegs_c3rom_names[] = { 0 }; +const char *g_kegs_c4rom_names[] = { 0 }; +const char *g_kegs_c5rom_names[] = { 0 }; +const char *g_kegs_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", + "DISK.ROM", "diskII.prom", 0 }; +const char *g_kegs_c7rom_names[] = { 0 }; + +const char **g_kegs_rom_card_list[8] = { + 0, g_kegs_c1rom_names, + g_kegs_c2rom_names, g_kegs_c3rom_names, + g_kegs_c4rom_names, g_kegs_c5rom_names, + g_kegs_c6rom_names, g_kegs_c7rom_names }; + +byte g_rom_c600_rom01_diffs[256] = { + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, + 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, + 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, + 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, + 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, + 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, + 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, + 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, + 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, + 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, + 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, + 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 +}; + +void +load_roms() +{ + char name_buf[256]; + struct stat stat_buf; + const char **names_ptr; + int more_than_8mb; + int changed_rom; + int len; + int fd; + int ret; + int i; + + g_rom_version = 0; + setup_kegs_file(&name_buf[0], (int)sizeof(name_buf), 0, + &g_kegs_rom_names[0]); + fd = open(name_buf, O_RDONLY | O_BINARY); + if(fd < 0) { + printf("Open ROM file %s failed:%d, errno:%d\n", name_buf, fd, + errno); + my_exit(-3); + } + + ret = fstat(fd, &stat_buf); + if(ret != 0) { + fprintf(stderr, "fstat returned %d on fd %d, errno: %d\n", + ret, fd, errno); + my_exit(2); + } + + len = stat_buf.st_size; + if(len == 128*1024) { + g_rom_version = 1; + g_mem_size_base = 256*1024; + ret = read(fd, &g_rom_fc_ff_ptr[2*65536], len); + } else if(len == 256*1024) { + g_rom_version = 3; + g_mem_size_base = 1024*1024; + ret = read(fd, &g_rom_fc_ff_ptr[0], len); + } else { + fprintf(stderr, "ROM size %d not 128K or 256K\n", len); + my_exit(4); + } + + printf("Read: %d bytes of ROM\n", ret); + if(ret != len) { + printf("errno: %d\n", errno); + my_exit(-3); + } + close(fd); + + memset(&g_rom_cards_ptr[0], 0, 256*16); + + /* initialize c600 rom to be diffs from the real ROM, to build-in */ + /* Apple II compatibility without distributing ROMs */ + for(i = 0; i < 256; i++) { + g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ + g_rom_c600_rom01_diffs[i]; + } + if(g_rom_version >= 3) { + /* some patches */ + g_rom_cards_ptr[0x61b] ^= 0x40; + g_rom_cards_ptr[0x61c] ^= 0x33; + g_rom_cards_ptr[0x632] ^= 0xc0; + g_rom_cards_ptr[0x633] ^= 0x33; + } + + for(i = 1; i < 8; i++) { + names_ptr = g_kegs_rom_card_list[i]; + if(names_ptr == 0) { + continue; + } + if(*names_ptr == 0) { + continue; + } + + setup_kegs_file(&name_buf[0], (int)sizeof(name_buf), 1, + names_ptr); + + if(name_buf[0] != 0) { + fd = open(name_buf, O_RDONLY | O_BINARY); + if(fd < 0) { + printf("Open card ROM file %s failed: %d " + "err:%d\n", name_buf, fd, errno); + my_exit(-3); + } + + len = 256; + ret = read(fd, &g_rom_cards_ptr[i*0x100], len); + + if(ret != len) { + printf("errno: %d, expected %d, got %d\n", + errno, len, ret); + my_exit(-3); + } + close(fd); + } + } + + more_than_8mb = (g_mem_size_exp > 0x800000); + /* Only do the patch if users wants more than 8MB of expansion mem */ + + changed_rom = 0; + if(g_rom_version == 1) { + /* make some patches to ROM 01 */ +#if 0 + /* 1: Patch ROM selftest to not do speed test */ + printf("Patching out speed test failures from ROM 01\n"); + g_rom_fc_ff_ptr[0x3785a] = 0x18; + changed_rom = 1; +#endif + +#if 0 + /* 2: Patch ROM selftests not to do tests 2,4 */ + /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ + g_rom_fc_ff_ptr[0x371e9] = 0xf5; + g_rom_fc_ff_ptr[0x371ea] = 0xff; + changed_rom = 1; +#endif + + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30302] = 0xdf; + g_rom_fc_ff_ptr[0x30314] = 0xdf; + g_rom_fc_ff_ptr[0x3031c] = 0x00; + changed_rom = 1; + } + + /* Patch ROM selftest to not do ROM cksum if any changes*/ + if(changed_rom) { + g_rom_fc_ff_ptr[0x37a06] = 0x18; + g_rom_fc_ff_ptr[0x37a07] = 0x18; + } + } else if(g_rom_version == 3) { + /* patch ROM 03 */ + printf("Patching ROM 03 smartport bug\n"); + /* 1: Patch Smartport code to fix a stupid bug */ + /* that causes it to write the IWM status reg into c036, */ + /* which is the system speed reg...it's "safe" since */ + /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ + /* it might have turned on shadowing in all banks! */ + g_rom_fc_ff_ptr[0x357c9] = 0x00; + changed_rom = 1; + +#if 0 + /* patch ROM 03 to not to speed test */ + /* skip fast speed test */ + g_rom_fc_ff_ptr[0x36ad7] = 0x18; + g_rom_fc_ff_ptr[0x36ad8] = 0x18; + changed_rom = 1; +#endif + +#if 0 + /* skip slow speed test */ + g_rom_fc_ff_ptr[0x36ae7] = 0x18; + g_rom_fc_ff_ptr[0x36ae8] = 0x6b; + changed_rom = 1; +#endif + +#if 0 + /* 4: Patch ROM 03 selftests not to do tests 1-4 */ + g_rom_fc_ff_ptr[0x364a9] = 0xf0; + g_rom_fc_ff_ptr[0x364aa] = 0xff; + changed_rom = 1; +#endif + + /* ROM tests are in ff/6403-642x, where 6403 = addr of */ + /* test 1, etc. */ + + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30b] = 0xdf; + g_rom_fc_ff_ptr[0x31d] = 0xdf; + g_rom_fc_ff_ptr[0x325] = 0x00; + changed_rom = 1; + } + + if(changed_rom) { + /* patch ROM 03 selftest to not do ROM cksum */ + g_rom_fc_ff_ptr[0x36cb0] = 0x18; + g_rom_fc_ff_ptr[0x36cb1] = 0x18; + } + + } +} + +void +do_debug_unix() +{ + char localbuf[LINE_SIZE]; + word32 offset, len; + int fd, ret; + int load, save; + int i; + + load = 0; save = 0; + switch(*line_ptr++) { + case 'l': case 'L': + printf("Loading.."); + load = 1; + break; + case 's': case 'S': + printf("Saving..."); + save = 1; + break; + default: + printf("Unknown unix command: %c\n", *(line_ptr-1)); + *line_ptr = 0; + return; + } + while(*line_ptr == ' ' || *line_ptr == '\t') { + line_ptr++; + } + i = 0; + while(i < LINE_SIZE) { + localbuf[i++] = *line_ptr++; + if(*line_ptr==' ' || *line_ptr=='\t' || *line_ptr == '\n') { + break; + } + } + localbuf[i] = 0; + + + printf("About to open: %s,len: %d\n", localbuf, (int)strlen(localbuf)); + if(load) { + fd = open(localbuf,O_RDONLY | O_BINARY); + } else { + fd = open(localbuf,O_WRONLY | O_CREAT | O_BINARY, 0x1b6); + } + if(fd < 0) { + printf("Open %s failed: %d\n", localbuf, fd); + printf("errno: %d\n", errno); + return; + } + if(load) { + offset = a1 & 0xffff; + len = 0x20000 - offset; + } else { + if(old_mode == '.') { + len = a2 - a1 + 1; + } else { + len = 0x100; + } + } + if(load) { + if(a1bank >= 0xe0 && a1bank < 0xe2) { + ret = read(fd,&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); + } else { + ret = read(fd,&g_memory_ptr[(a1bank << 16) + a1],len); + } + } else { + if(a1bank >= 0xe0 && a1bank < 0xe2) { + ret = write(fd,&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); + } else { + ret = write(fd,&g_memory_ptr[(a1bank << 16) + a1],len); + } + } + printf("Read/write: addr %06x for %04x bytes, ret: %x bytes\n", + (a1bank << 16) + a1, len, ret); + if(ret < 0) { + printf("errno: %d\n", errno); + } + a1 = a1 + ret; +} + +void +do_debug_load() +{ + printf("Sorry, can't load now\n"); +} + + +int +do_dis(FILE *outfile, word32 kpc, int accsize, int xsize, + int op_provided, word32 instr) +{ + char buffer[150]; + const char *out; + int args, type; + int opcode; + word32 val; + word32 oldkpc; + word32 dtype; + int signed_val; + + oldkpc = kpc; + if(op_provided) { + opcode = (instr >> 24) & 0xff; + } else { + opcode = (int)get_memory_c(kpc, 0) & 0xff; + } + + kpc++; + + dtype = disas_types[opcode]; + out = disas_opcodes[opcode]; + type = dtype & 0xff; + args = dtype >> 8; + + if(args > 3) { + if(args == 4) { + args = accsize; + } else if(args == 5) { + args = xsize; + } + } + + val = -1; + switch(args) { + case 0: + val = 0; + break; + case 1: + if(op_provided) { + val = instr & 0xff; + } else { + val = get_memory_c(kpc, 0); + } + break; + case 2: + if(op_provided) { + val = instr & 0xffff; + } else { + val = get_memory16_c(kpc, 0); + } + break; + case 3: + if(op_provided) { + val = instr & 0xffffff; + } else { + val = get_memory24_c(kpc, 0); + } + break; + default: + fprintf(stderr, "args out of rang: %d, opcode: %08x\n", + args, opcode); + break; + } + kpc += args; + + if(!op_provided) { + instr = (opcode << 24) | (val & 0xffffff); + } + + switch(type) { + case ABS: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSX: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x,X",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSY: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x,Y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSLONG: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%06x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSIND: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%04x)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSXIND: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%04x,X)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case IMPLY: + if(args != 0) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s",out); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ACCUM: + if(args != 0) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s",out); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case IMMED: + if(args == 1) { + sprintf(buffer,"%s\t#$%02x",out,val); + } else if(args == 2) { + sprintf(buffer,"%s\t#$%04x",out,val); + } else { + printf("arg # mismatch for opcode %x\n", opcode); + } + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case JUST8: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOC: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCX: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,X",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,Y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case LONG: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%06x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case LONGX: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%06x,X",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCIND: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCINDY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x),Y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCXIND: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x,X)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCBRAK: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t[$%02x]",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCBRAKY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t[$%02x],y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP8: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + signed_val = (signed char)val; + sprintf(buffer,"%s\t$%04x",out, + (word32)(kpc+(signed_val)) & 0xffff); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP8S: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,S",out,(word32)(byte)(val)); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP8SINDY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x,S),Y",out,(word32)(byte)(val)); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP16: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x", out, + (word32)(kpc+(signed)(word16)(val)) & 0xffff); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case MVPMVN: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,$%02x",out,val&0xff,val>>8); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case SEPVAL: + case REPVAL: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t#$%02x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + default: + printf("argument type: %d unexpected\n", type); + break; + } + + return(args+1); +} + +void +show_line(FILE *outfile, word32 kaddr, word32 operand, int size, + char *string) +{ + int i; + int opcode; + + fprintf(outfile, "%02x/%04x: ", kaddr >> 16, kaddr & 0xffff); + opcode = (operand >> 24) & 0xff; + fprintf(outfile,"%02x ", opcode); + + for(i=1;i> 8; + } + for(;i<5;i++) { + fprintf(outfile, " "); + } + fprintf(outfile,"%s\n", string); +} + +void +halt_printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + set_halt(1); +} + +void +halt2_printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + set_halt(2); +} + diff --git a/src/disas.h b/src/disas.h new file mode 100644 index 0000000..f83cd90 --- /dev/null +++ b/src/disas.h @@ -0,0 +1,210 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_disas_h[] = "@(#)$KmKId: disas.h,v 1.10 2002-11-19 03:10:38-05 kadickey Exp $"; + +enum { + ABS = 1, + ABSX, + ABSY, + ABSLONG, + ABSIND, + ABSXIND, + IMPLY, + ACCUM, + IMMED, + JUST8, + DLOC, + DLOCX, + DLOCY, + LONG, + LONGX, + DLOCIND, + DLOCINDY, + DLOCXIND, + DLOCBRAK, + DLOCBRAKY, + DISP8, + DISP8S, + DISP8SINDY, + DISP16, + MVPMVN, + REPVAL, + SEPVAL +}; + + +const char * const disas_opcodes[256] = { + "BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", /* 00-07 */ + "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", /* 08-0f */ + "BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", /* 10-17 */ + "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", /* 18-1f */ + "JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", /* 20-27 */ + "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", /* 28-2f */ + "BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", /* 30-37 */ + "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", /* 38-3f */ + "RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", /* 40-47 */ + "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", /* 48-4f */ + "BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", /* 50-57 */ + "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", /* 58-5f */ + "RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", /* 60-67 */ + "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", /* 68-6f */ + "BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", /* 70-77 */ + "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", /* 78-7f */ + "BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", /* 80-87 */ + "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", /* 88-8f */ + "BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", /* 90-97 */ + "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", /* 98-9f */ + "LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", /* a0-a7 */ + "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", /* a8-af */ + "BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", /* b0-b7 */ + "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", /* b8-bf */ + "CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", /* c0-c7 */ + "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", /* c8-cf */ + "BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", /* d0-d7 */ + "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", /* d8-df */ + "CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", /* e0-e7 */ + "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", /* e8-ef */ + "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", /* f0-f7 */ + "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC", /* f8-ff */ +}; + + +const word32 disas_types[256] = { + JUST8+0x100, DLOCXIND+0x100, /* 00-01 */ + JUST8+0x100, DISP8S+0x100, /* 02-03 */ + DLOC+0x100, DLOC+0x100, /* 04-05 */ + DLOC+0x100, DLOCBRAK+0x100, /* 06-07 */ + IMPLY+0x000, IMMED+0x400, /* 08-9 */ + ACCUM+0x000, IMPLY+0x000, /* 0a-b */ + ABS+0x200, ABS+0x200, /* c-d */ + ABS+0x200, LONG+0x300, /* e-f */ + DISP8+0x100, DLOCINDY+0x100, /* 10-11 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* 12-13 */ + DLOC+0x100, DLOCX+0x100, /* 14-15 */ + DLOCX+0x100, DLOCBRAKY+0x100, /* 16-17 */ + IMPLY+0x000, ABSY+0x200, /* 18-19 */ + ACCUM+0x000, IMPLY+0x000, /* 1a-1b */ + ABS+0x200, ABSX+0x200, /* 1c-1d */ + ABSX+0x200, LONGX+0x300, /* 1e-1f */ + ABS+0x200, DLOCXIND+0x100, /* 20-21 */ + ABSLONG+0x300, DISP8S+0x100, /* 22-23 */ + DLOC+0x100, DLOC+0x100, /* 24-25 */ + DLOC+0x100, DLOCBRAK+0x100, /* 26-27 */ + IMPLY+0x000, IMMED+0x400, /* 28-29 */ + ACCUM+0x000, IMPLY+0x000, /* 2a-2b */ + ABS+0x200, ABS+0x200, /* 2c-2d */ + ABS+0x200, LONG+0x300, /* 2e-2f */ + DISP8+0x100, DLOCINDY+0x100, /* 30-31 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* 32-33 */ + DLOCX+0x100, DLOCX+0x100, /* 34-35 */ + DLOCX+0x100, DLOCBRAKY+0x100, /* 36-37 */ + IMPLY+0x000, ABSY+0x200, /* 38-39 */ + ACCUM+0x000, IMPLY+0x000, /* 3a-3b */ + ABSX+0x200, ABSX+0x200, /* 3c-3d */ + ABSX+0x200, LONGX+0x300, /* 3e-3f */ + IMPLY+0x000, DLOCXIND+0x100, /* 40-41 */ + JUST8+0x100, DISP8S+0x100, /* 42-43 */ + MVPMVN+0x200, DLOC+0x100, /* 44-45 */ + DLOC+0x100, DLOCBRAK+0x100, /* 46-47 */ + IMPLY+0x000, IMMED+0x400, /* 48-49 */ + ACCUM+0x000, IMPLY+0x000, /* 4a-4b */ + ABS+0x200, ABS+0x200, /* 4c-4d */ + ABS+0x200, LONG+0x300, /* 4e-4f */ + DISP8+0x100, DLOCINDY+0x100, /* 50-51 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* 52-53 */ + MVPMVN+0x200, DLOCX+0x100, /* 54-55 */ + DLOCX+0x100, DLOCBRAKY+0x100, /* 56-57 */ + IMPLY+0x000, ABSY+0x200, /* 58-59 */ + IMPLY+0x000, IMPLY+0x000, /* 5a-5b */ + LONG+0x300, ABSX+0x200, /* 5c-5d */ + ABSX+0x200, LONGX+0x300, /* 5e-5f */ + IMPLY+0x000, DLOCXIND+0x100, /* 60-61 */ + DISP16+0x200, DISP8S+0x100, /* 62-63 */ + DLOC+0x100, DLOC+0x100, /* 64-65 */ + DLOC+0x100, DLOCBRAK+0x100, /* 66-67 */ + IMPLY+0x000, IMMED+0x400, /* 68-69 */ + ACCUM+0x000, IMPLY+0x000, /* 6a-6b */ + ABSIND+0x200, ABS+0x200, /* 6c-6d */ + ABS+0x200, LONG+0x300, /* 6e-6f */ + DISP8+0x100, DLOCINDY+0x100, /* 70-71 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* 72-73 */ + DLOCX+0x100, DLOCX+0x100, /* 74-75 */ + DLOCX+0x100, DLOCBRAKY+0x100, /* 76-77 */ + IMPLY+0x000, ABSY+0x200, /* 78-79 */ + IMPLY+0x000, IMPLY+0x000, /* 7a-7b */ + ABSXIND+0x200, ABSX+0x200, /* 7c-7d */ + ABSX+0x200, LONGX+0x300, /* 7e-7f */ + DISP8+0x100, DLOCXIND+0x100, /* 80-81 */ + DISP16+0x200, DISP8S+0x100, /* 82-83 */ + DLOC+0x100, DLOC+0x100, /* 84-85 */ + DLOC+0x100, DLOCBRAK+0x100, /* 86-87 */ + IMPLY+0x000, IMMED+0x400, /* 88-89 */ + IMPLY+0x000, IMPLY+0x000, /* 8a-8b */ + ABS+0x200, ABS+0x200, /* 8c-8d */ + ABS+0x200, LONG+0x300, /* 8e-8f */ + DISP8+0x100, DLOCINDY+0x100, /* 90-91 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* 92-93 */ + DLOCX+0x100, DLOCX+0x100, /* 94-95 */ + DLOCY+0x100, DLOCBRAKY+0x100, /* 96-97 */ + IMPLY+0x000, ABSY+0x200, /* 98-99 */ + IMPLY+0x000, IMPLY+0x000, /* 9a-9b */ + ABS+0x200, ABSX+0x200, /* 9c-9d */ + ABSX+0x200, LONGX+0x300, /* 9e-9f */ + IMMED+0x500, DLOCXIND+0x100, /* a0-a1 */ + IMMED+0x500, DISP8S+0x100, /* a2-a3 */ + DLOC+0x100, DLOC+0x100, /* a4-a5 */ + DLOC+0x100, DLOCBRAK+0x100, /* a6-a7 */ + IMPLY+0x000, IMMED+0x400, /* a8-a9 */ + IMPLY+0x000, IMPLY+0x000, /* aa-ab */ + ABS+0x200, ABS+0x200, /* ac-ad */ + ABS+0x200, LONG+0x300, /* ae-af */ + DISP8+0x100, DLOCINDY+0x100, /* b0-b1 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* b2-b3 */ + DLOCX+0x100, DLOCX+0x100, /* b4-b5 */ + DLOCY+0x100, DLOCBRAKY+0x100, /* b6-b7 */ + IMPLY+0x000, ABSY+0x200, /* b8-b9 */ + IMPLY+0x000, IMPLY+0x000, /* ba-bb */ + ABSX+0x200, ABSX+0x200, /* bc-bd */ + ABSY+0x200, LONGX+0x300, /* be-bf */ + IMMED+0x500, DLOCXIND+0x100, /* c0-c1 */ + REPVAL+0x100, DISP8S+0x100, /* c2-c3 */ + DLOC+0x100, DLOC+0x100, /* c4-c5 */ + DLOC+0x100, DLOCBRAK+0x100, /* c6-c7 */ + IMPLY+0x000, IMMED+0x400, /* c8-c9 */ + IMPLY+0x000, IMPLY+0x000, /* ca-cb */ + ABS+0x200, ABS+0x200, /* cc-cd */ + ABS+0x200, LONG+0x300, /* ce-cf */ + DISP8+0x100, DLOCINDY+0x100, /* d0-d1 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* d2-d3 */ + DLOC+0x100, DLOCX+0x100, /* d4-d5 */ + DLOCX+0x100, DLOCBRAKY+0x100, /* d6-d7 */ + IMPLY+0x000, ABSY+0x200, /* d8-d9 */ + IMPLY+0x000, IMPLY+0x000, /* da-db */ + ABSIND+0x200, ABSX+0x200, /* dc-dd */ + ABSX+0x200, LONGX+0x300, /* de-df */ + IMMED+0x500, DLOCXIND+0x100, /* e0-e1 */ + SEPVAL+0x100, DISP8S+0x100, /* e2-e3 */ + DLOC+0x100, DLOC+0x100, /* e4-e5 */ + DLOC+0x100, DLOCBRAK+0x100, /* e6-e7 */ + IMPLY+0x000, IMMED+0x400, /* e8-e9 */ + IMPLY+0x000, IMPLY+0x000, /* ea-eb */ + ABS+0x200, ABS+0x200, /* ec-ed */ + ABS+0x200, LONG+0x300, /* ee-ef */ + DISP8+0x100, DLOCINDY+0x100, /* f0-f1 */ + DLOCIND+0x100, DISP8SINDY+0x100, /* f2-f3 */ + IMMED+0x200, DLOCX+0x100, /* f4-f5 */ + DLOCX+0x100, DLOCBRAKY+0x100, /* f6-f7 */ + IMPLY+0x000, ABSY+0x200, /* f8-f9 */ + IMPLY+0x000, IMPLY+0x000, /* fa-fb */ + ABSXIND+0x200, ABSX+0x200, /* fc-fd */ + ABSX+0x200, LONGX+0x300, /* fe-ff */ +}; + diff --git a/src/engine_c.c b/src/engine_c.c new file mode 100644 index 0000000..cbeedec --- /dev/null +++ b/src/engine_c.c @@ -0,0 +1,1007 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_engine_c_c[] = "@(#)$KmKId: engine_c.c,v 1.51 2004-01-10 15:50:15-05 kentd Exp $"; + +#include "defc.h" +#include "protos_engine_c.h" + +#if 0 +# define LOG_PC +/* define FCYCS_PTR_FCYCLES_ROUND_SLOW to get accurate 1MHz write to slow mem*/ +/* this might help joystick emulation in some Apple //gs games like */ +/* Madness */ +# define FCYCS_PTR_FCYCLES_ROUND_SLOW FCYCLES_ROUND; *fcycs_ptr = fcycles; +#endif + +#ifndef FCYCS_PTR_FCYCLES_ROUND_SLOW +# define FCYCS_PTR_FCYCLES_ROUND_SLOW +#endif + +extern int halt_sim; +extern int g_code_red; +extern int g_ignore_halts; +extern double g_fcycles_stop; +extern double g_last_vbl_dcycs; +extern int g_wait_pending; +extern int g_irq_pending; +extern int g_testing; +extern int g_num_brk; +extern int g_num_cop; +extern byte *g_slow_memory_ptr; +extern byte *g_memory_ptr; +extern byte *g_rom_fc_ff_ptr; +extern byte *g_rom_cards_ptr; +extern byte *g_dummy_memory1_ptr; + +extern int g_num_breakpoints; +extern word32 g_breakpts[]; + +extern Pc_log *log_pc_ptr; +extern Pc_log *log_pc_start_ptr; +extern Pc_log *log_pc_end_ptr; + +int size_tab[] = { +#include "size_c.h" +}; + +int bogus[] = { + 0, +#include "op_routs.h" +}; + +#define FINISH(arg1, arg2) g_ret1 = arg1; g_ret2 = arg2; goto finish; +#define INC_KPC_1 kpc = (kpc & 0xff0000) + ((kpc + 1) & 0xffff); +#define INC_KPC_2 kpc = (kpc & 0xff0000) + ((kpc + 2) & 0xffff); +#define INC_KPC_3 kpc = (kpc & 0xff0000) + ((kpc + 3) & 0xffff); +#define INC_KPC_4 kpc = (kpc & 0xff0000) + ((kpc + 4) & 0xffff); + +#define CYCLES_PLUS_1 fcycles += fplus_1; +#define CYCLES_PLUS_2 fcycles += fplus_2; +#define CYCLES_PLUS_3 fcycles += fplus_3; +#define CYCLES_PLUS_4 fcycles += (fplus_1 + fplus_3); +#define CYCLES_PLUS_5 fcycles += (fplus_2 + fplus_3); +#define CYCLES_MINUS_1 fcycles -= fplus_1; +#define CYCLES_MINUS_2 fcycles -= fplus_2; + +#define CYCLES_FINISH fcycles = g_fcycles_stop + fplus_1; + +#define FCYCLES_ROUND fcycles = (int)(fcycles + fplus_x_m1); + +#define LOG_PC_MACRO() \ + tmp_pc_ptr = log_pc_ptr++; \ + tmp_pc_ptr->dbank_kpc = (dbank << 24) + kpc; \ + tmp_pc_ptr->instr = (opcode << 24) + arg_ptr[1] + \ + (arg_ptr[2] << 8) + (arg_ptr[3] << 16); \ + tmp_pc_ptr->psr_acc = ((psr & ~(0x82)) << 16) + acc + \ + (neg << 23) + ((!zero) << 17); \ + tmp_pc_ptr->xreg_yreg = (xreg << 16) + yreg; \ + tmp_pc_ptr->stack_direct = (stack << 16) + direct; \ + tmp_pc_ptr->dcycs = fcycles + g_last_vbl_dcycs - fplus_2; \ + if(log_pc_ptr >= log_pc_end_ptr) { \ + /*halt2_printf("log_pc oflow %f\n", tmp_pc_ptr->dcycs);*/ \ + log_pc_ptr = log_pc_start_ptr; \ + } + +#define GET_1BYTE_ARG arg = arg_ptr[1]; +#define GET_2BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8); +#define GET_3BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8) + (arg_ptr[3]<<16); + +/* HACK HACK HACK */ +#define UPDATE_PSR(dummy, old_psr) \ + if(psr & 0x100) { \ + psr |= 0x30; \ + stack = 0x100 + (stack & 0xff); \ + } \ + if((old_psr ^ psr) & 0x10) { \ + if(psr & 0x10) { \ + xreg = xreg & 0xff; \ + yreg = yreg & 0xff; \ + } \ + } \ + if(((psr & 0x4) == 0) && g_irq_pending) { \ + FINISH(RET_IRQ, 0); \ + } \ + if((old_psr ^ psr) & 0x20) { \ + goto recalc_accsize; \ + } + +extern Page_info page_info_rd_wr[]; +extern word32 slow_mem_changed[]; + +#define GET_MEMORY8(addr,dest) \ + addr_latch = (addr); \ + CYCLES_PLUS_1; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if(wstat & (1 << (31 - BANK_IO_BIT))) { \ + fcycles_tmp1 = fcycles; \ + dest = get_memory8_io_stub((addr), stat, \ + &fcycles_tmp1, fplus_x_m1); \ + fcycles = fcycles_tmp1; \ + } else { \ + dest = *ptr; \ + } + +#define GET_MEMORY(addr,dest) GET_MEMORY8(addr, dest) + +#define GET_MEMORY16(addr, dest, in_bank) \ + save_addr = addr; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat & (1 << (31 - BANK_IO_BIT))) || (((addr) & 0xff) == 0xff)) { \ + fcycles_tmp1 = fcycles; \ + dest = get_memory16_pieces_stub((addr), stat, \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_2; \ + dest = ptr[0] + (ptr[1] << 8); \ + } \ + addr_latch = save_addr; + +#define GET_MEMORY24(addr, dest, in_bank) \ + save_addr = addr; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat & (1 << (31 - BANK_IO_BIT))) || (((addr) & 0xfe) == 0xfe)) { \ + fcycles_tmp1 = fcycles; \ + dest = get_memory24_pieces_stub((addr), stat, \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_3; \ + dest = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16); \ + } \ + addr_latch = save_addr; + +#define GET_MEMORY_DIRECT_PAGE16(addr, dest) \ + save_addr = addr; \ + if(psr & 0x100) { \ + if((direct & 0xff) == 0) { \ + save_addr = (save_addr & 0xff) + direct; \ + } \ + } \ + if((psr & 0x100) && (((addr) & 0xff) == 0xff)) { \ + GET_MEMORY8(save_addr, getmem_tmp); \ + save_addr = (save_addr + 1) & 0xffff; \ + if((direct & 0xff) == 0) { \ + save_addr = (save_addr & 0xff) + direct; \ + } \ + GET_MEMORY8(save_addr, dest); \ + dest = (dest << 8) + getmem_tmp; \ + } else { \ + GET_MEMORY16(save_addr, dest, 1); \ + } + + +#define PUSH8(arg) \ + SET_MEMORY8(stack, arg); \ + stack--; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; + +#define PUSH16(arg) \ + if((stack & 0xfe) == 0) { \ + /* stack will cross page! */ \ + PUSH8((arg) >> 8); \ + PUSH8(arg); \ + } else { \ + stack -= 2; \ + stack = stack & 0xffff; \ + SET_MEMORY16(stack + 1, arg, 1); \ + } + +#define PUSH16_UNSAFE(arg) \ + save_addr = (stack - 1) & 0xffff; \ + stack -= 2; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; \ + SET_MEMORY16(save_addr, arg, 1); + +#define PUSH24_UNSAFE(arg) \ + save_addr = (stack - 2) & 0xffff; \ + stack -= 3; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; \ + SET_MEMORY24(save_addr, arg, 1); + +#define PULL8(dest) \ + stack++; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; \ + GET_MEMORY8(stack, dest); + +#define PULL16(dest) \ + if((stack & 0xfe) == 0xfe) { /* page cross */ \ + PULL8(dest); \ + PULL8(pull_tmp); \ + dest = (pull_tmp << 8) + dest; \ + } else { \ + GET_MEMORY16(stack + 1, dest, 1); \ + stack = (stack + 2) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + } + +#define PULL16_UNSAFE(dest) \ + stack = (stack + 1) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + GET_MEMORY16(stack, dest, 1); \ + stack = (stack + 1) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } + +#define PULL24(dest) \ + if((stack & 0xfc) == 0xfc) { /* page cross */ \ + PULL8(dest); \ + PULL8(pull_tmp); \ + pull_tmp = (pull_tmp << 8) + dest; \ + PULL8(dest); \ + dest = (dest << 16) + pull_tmp; \ + } else { \ + GET_MEMORY24(stack + 1, dest, 1); \ + stack = (stack + 3) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + } + +#define SET_MEMORY8(addr, val) \ + CYCLES_PLUS_1; \ + stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if(wstat) { \ + fcycles_tmp1 = fcycles; \ + set_memory8_io_stub((addr), val, stat, &fcycles_tmp1, \ + fplus_x_m1); \ + fcycles = fcycles_tmp1; \ + } else { \ + *ptr = val; \ + } + + + + + +#define SET_MEMORY16(addr, val, in_bank) \ + stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat) || (((addr) & 0xff) == 0xff)) { \ + fcycles_tmp1 = fcycles; \ + set_memory16_pieces_stub((addr), (val), \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_2; \ + ptr[0] = (val); \ + ptr[1] = (val) >> 8; \ + } + +#define SET_MEMORY24(addr, val, in_bank) \ + stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat) || (((addr) & 0xfe) == 0xfe)) { \ + fcycles_tmp1 = fcycles; \ + set_memory24_pieces_stub((addr), (val), \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_3; \ + ptr[0] = (val); \ + ptr[1] = (val) >> 8; \ + ptr[2] = (val) >> 16; \ + } + +void +check_breakpoints(word32 addr) +{ + int count; + int i; + + count = g_num_breakpoints; + for(i = 0; i < count; i++) { + if(g_breakpts[i] == addr) { + halt2_printf("Hit breakpoint at %06x\n", addr); + } + } +} + +word32 +get_memory8_io_stub(word32 addr, byte *stat, double *fcycs_ptr, + double fplus_x_m1) +{ + double fcycles; + word32 wstat; + byte *ptr; + + wstat = PTR2WORD(stat) & 0xff; + if(wstat & BANK_BREAK) { + check_breakpoints(addr); + } + fcycles = *fcycs_ptr; + if(wstat & BANK_IO2_TMP) { + FCYCLES_ROUND; + *fcycs_ptr = fcycles; + return get_memory_io((addr), fcycs_ptr); + } else { + ptr = stat - wstat + (addr & 0xff); + return *ptr; + } +} + +word32 +get_memory16_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) +{ + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1; + word32 wstat; + word32 addr_latch; + word32 ret; + word32 tmp1; + + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + GET_MEMORY8(addr, tmp1); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + GET_MEMORY8(addrp1, ret); + *fcycs_ptr = fcycles; + return (ret << 8) + (tmp1); +} + +word32 +get_memory24_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) +{ + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1, addrp2; + word32 wstat; + word32 addr_latch; + word32 ret; + word32 tmp1; + word32 tmp2; + + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + GET_MEMORY8(addr, tmp1); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + GET_MEMORY8(addrp1, tmp2); + addrp2 = addr + 2; + if(in_bank) { + addrp2 = (addr & 0xff0000) + (addrp2 & 0xffff); + } + GET_MEMORY8(addrp2, ret); + *fcycs_ptr = fcycles; + return (ret << 16) + (tmp2 << 8) + tmp1; +} + +void +set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, + double fplus_x_m1) +{ + double fcycles; + word32 setmem_tmp1; + word32 tmp1, tmp2; + byte *ptr; + word32 wstat; + + wstat = PTR2WORD(stat) & 0xff; + if(wstat & (1 << (31 - BANK_BREAK_BIT))) { + check_breakpoints(addr); + } + ptr = stat - wstat + ((addr) & 0xff); \ + fcycles = *fcycs_ptr; + if(wstat & (1 << (31 - BANK_IO2_BIT))) { + FCYCLES_ROUND; + *fcycs_ptr = fcycles; + set_memory_io((addr), val, fcycs_ptr); + } else if(wstat & (1 << (31 - BANK_SHADOW_BIT))) { + FCYCS_PTR_FCYCLES_ROUND_SLOW; + tmp1 = (addr & 0xffff); + setmem_tmp1 = g_slow_memory_ptr[tmp1]; + *ptr = val; + if(setmem_tmp1 != ((val) & 0xff)) { + g_slow_memory_ptr[tmp1] = val; + slow_mem_changed[tmp1 >> CHANGE_SHIFT] |= + (1 << (31-((tmp1 >> SHIFT_PER_CHANGE) & 0x1f))); + } + } else if(wstat & (1 << (31 - BANK_SHADOW2_BIT))) { + FCYCS_PTR_FCYCLES_ROUND_SLOW; + tmp2 = (addr & 0xffff); + tmp1 = 0x10000 + tmp2; + setmem_tmp1 = g_slow_memory_ptr[tmp1]; + *ptr = val; + if(setmem_tmp1 != ((val) & 0xff)) { + g_slow_memory_ptr[tmp1] = val; + slow_mem_changed[tmp2 >>CHANGE_SHIFT] |= + (1 <<(31-((tmp2 >> SHIFT_PER_CHANGE) & 0x1f))); + } + } else { + /* breakpoint only */ + *ptr = val; + } +} + +void +set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) +{ + byte *ptr; + byte *stat; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1; + word32 wstat; + + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + SET_MEMORY8(addr, val); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + SET_MEMORY8(addrp1, val >> 8); + + *fcycs_ptr = fcycles; +} + +void +set_memory24_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) +{ + byte *ptr; + byte *stat; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1, addrp2; + word32 wstat; + + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + SET_MEMORY8(addr, val); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + SET_MEMORY8(addrp1, val >> 8); + addrp2 = addr + 2; + if(in_bank) { + addrp2 = (addr & 0xff0000) + (addrp2 & 0xffff); + } + SET_MEMORY8(addrp2, val >> 16); + + *fcycs_ptr = fcycles; +} + + +word32 +get_memory_c(word32 addr, int cycs) +{ + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addr_latch; + word32 wstat; + word32 ret; + + fcycles = 0; + fplus_1 = 0; + fplus_x_m1 = 0; + GET_MEMORY8(addr, ret); + return ret; +} +#if 0 + stat = page_info[(addr>>8) & 0xffff].rd; + ptr = (byte *)((stat & 0xffffff00) | (addr & 0xff)); + if(stat & (1 << (31 -BANK_IO_BIT))) { + return get_memory_io(addr, &in_fcycles); + } + return *ptr; +#endif + +word32 +get_memory16_c(word32 addr, int cycs) +{ + double fcycs; + + fcycs = 0; + return get_memory_c(addr, fcycs) + + (get_memory_c(addr+1, fcycs) << 8); +} + +word32 +get_memory24_c(word32 addr, int cycs) +{ + double fcycs; + + fcycs = 0; + return get_memory_c(addr, fcycs) + + (get_memory_c(addr+1, fcycs) << 8) + + (get_memory_c(addr+2, fcycs) << 16); +} + +void +set_memory_c(word32 addr, word32 val, int cycs) +{ + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 wstat; + + fcycles = 0; + fplus_1 = 0; + fplus_x_m1 = 0; + SET_MEMORY8(addr, val); +} +void +set_memory16_c(word32 addr, word32 val, int cycs) +{ + set_memory_c(addr, val, 0); + set_memory_c(addr + 1, val >> 8, 0); +} + +void +set_memory24_c(word32 addr, word32 val, int cycs) +{ + set_memory_c(addr, val, 0); + set_memory_c(addr + 1, val >> 8, 0); + set_memory_c(addr + 2, val >> 16, 0); +} + +word32 +do_adc_sbc8(word32 in1, word32 in2, word32 psr, int sub) +{ + word32 sum, carry, overflow; + word32 zero; + int decimal; + + overflow = 0; + decimal = psr & 8; + if(sub) { + in2 = (in2 ^ 0xff); + } + if(!decimal) { + sum = (in1 & 0xff) + in2 + (psr & 1); + overflow = ((sum ^ in2) >> 1) & 0x40; + } else { + /* decimal */ + sum = (in1 & 0xf) + (in2 & 0xf) + (psr & 1); + if(sub) { + if(sum < 0x10) { + sum = (sum - 0x6) & 0xf; + } + } else { + if(sum >= 0xa) { + sum = (sum - 0xa) | 0x10; + } + } + + sum = (in1 & 0xf0) + (in2 & 0xf0) + sum; + overflow = ((sum >> 2) ^ (sum >> 1)) & 0x40; + if(sub) { + if(sum < 0x100) { + sum = (sum + 0xa0) & 0xff; + } + } else { + if(sum >= 0xa0) { + sum += 0x60; + } + } + } + + zero = ((sum & 0xff) == 0); + carry = (sum >= 0x100); + if((in1 ^ in2) & 0x80) { + overflow = 0; + } + + psr = psr & (~0xc3); + psr = psr + (sum & 0x80) + overflow + (zero << 1) + carry; + + return (psr << 16) + (sum & 0xff); +} + +word32 +do_adc_sbc16(word32 in1, word32 in2, word32 psr, int sub) +{ + word32 sum, carry, overflow; + word32 tmp1, tmp2; + word32 zero; + int decimal; + + overflow = 0; + decimal = psr & 8; + if(!decimal) { + if(sub) { + in2 = (in2 ^ 0xffff); + } + sum = in1 + in2 + (psr & 1); + overflow = ((sum ^ in2) >> 9) & 0x40; + } else { + /* decimal */ + if(sub) { + tmp1 = do_adc_sbc8(in1 & 0xff, in2 & 0xff, psr, sub); + psr = (tmp1 >> 16); + tmp2 = do_adc_sbc8((in1 >> 8) & 0xff, + (in2 >> 8) & 0xff, psr, sub); + in2 = (in2 ^ 0xfffff); + } else { + tmp1 = do_adc_sbc8(in1 & 0xff, in2 & 0xff, psr, sub); + psr = (tmp1 >> 16); + tmp2 = do_adc_sbc8((in1 >> 8) & 0xff, + (in2 >> 8) &0xff, psr, sub); + } + sum = ((tmp2 & 0xff) << 8) + (tmp1 & 0xff) + + (((tmp2 >> 16) & 1) << 16); + overflow = (tmp2 >> 16) & 0x40; + } + + zero = ((sum & 0xffff) == 0); + carry = (sum >= 0x10000); + if((in1 ^ in2) & 0x8000) { + overflow = 0; + } + + psr = psr & (~0xc3); + psr = psr + ((sum & 0x8000) >> 8) + overflow + (zero << 1) + carry; + + return (psr << 16) + (sum & 0xffff); +} + +int g_ret1; +int g_ret2; + + +void +fixed_memory_ptrs_init() +{ + /* set g_slow_memory_ptr, g_rom_fc_ff_ptr, g_dummy_memory1_ptr, */ + /* and rom_cards_ptr */ + + g_slow_memory_ptr = memalloc_align(128*1024, 0); + g_dummy_memory1_ptr = memalloc_align(256, 1024); + g_rom_fc_ff_ptr = memalloc_align(256*1024, 1024); + g_rom_cards_ptr = memalloc_align(16*256, 1024); + +#if 0 + printf("g_memory_ptr: %08x, dummy_mem: %08x, slow_mem_ptr: %08x\n", + (word32)g_memory_ptr, (word32)g_dummy_memory1_ptr, + (word32)g_slow_memory_ptr); + printf("g_rom_fc_ff_ptr: %08x, g_rom_cards_ptr: %08x\n", + (word32)g_rom_fc_ff_ptr, (word32)g_rom_cards_ptr); + printf("page_info_rd = %08x, page_info_wr end = %08x\n", + (word32)&(page_info_rd_wr[0]), + (word32)&(page_info_rd_wr[PAGE_INFO_PAD_SIZE+0x1ffff].rd_wr)); +#endif +} + +word32 +get_itimer() +{ +#if defined(__i386) && defined(__GNUC__) + /* Here's my bad ia32 asm code to do rdtsc */ + /* Linux source uses: */ + /* asm volatile("rdtsc" : "=a"(ret) : : "edx"); */ + /* asm volatile("rdtsc" : "=%eax"(ret) : : "%edx"); */ + + /* GCC bug report 2001-03/msg00786.html used: */ + /*register word64 dtmp; */ + /*asm volatile ("rdtsc" : "=A" (dtmp)); */ + /*return (word32)dtmp; */ + + register word32 ret; + + asm volatile ("rdtsc;movl %%eax,%0" : "=r"(ret) : : "%eax","%edx"); + + return ret; +#else +# if defined(__POWERPC__) && defined(__GNUC__) + register word32 ret; + + asm volatile ("mftb %0" : "=r"(ret)); + return ret; +# else + return 0; +# endif +#endif +} + +void +set_halt_act(int val) +{ + if(val == 1 && g_ignore_halts) { + g_code_red++; + } else { + halt_sim |= val; + g_fcycles_stop = (double)0.0; + } +} + +void +clr_halt_act() +{ + halt_sim = 0; +} + +word32 +get_remaining_operands(word32 addr, word32 opcode, word32 psr, Fplus *fplus_ptr) +{ + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1, fplus_2, fplus_3; + double fplus_x_m1; + word32 addr_latch; + word32 wstat; + word32 save_addr; + word32 arg; + word32 addrp1; + int size; + + fcycles = 0; + fplus_1 = 0; + fplus_2 = 0; + fplus_3 = 0; + fplus_x_m1 = 0; + + size = size_tab[opcode]; + + addrp1 = (addr & 0xff0000) + ((addr + 1) & 0xffff); + switch(size) { + case 0: + arg = 0; /* no args */ + break; + case 1: + GET_MEMORY8(addrp1, arg); + break; /* 1 arg, already done */ + case 2: + GET_MEMORY16(addrp1, arg, 1); + break; + case 3: + GET_MEMORY24(addrp1, arg, 1); + break; + case 4: + if(psr & 0x20) { + GET_MEMORY8(addrp1, arg); + } else { + GET_MEMORY16(addrp1, arg, 1); + } + break; + case 5: + if(psr & 0x10) { + GET_MEMORY8(addrp1, arg); + } else { + GET_MEMORY16(addrp1, arg, 1); + } + break; + default: + printf("Unknown size: %d\n", size); + arg = 0; + exit(-2); + } + + return arg; +} + +#define FETCH_OPCODE \ + addr = kpc; \ + CYCLES_PLUS_2; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + arg_ptr = ptr; \ + opcode = *ptr; \ + if((wstat & (1 << (31-BANK_IO_BIT))) || ((addr & 0xff) > 0xfc)) {\ + if(wstat & BANK_BREAK) { \ + check_breakpoints(addr); \ + } \ + if((addr & 0xfffff0) == 0x00c700) { \ + if(addr == 0xc700) { \ + FINISH(RET_C700, 0); \ + } else if(addr == 0xc70a) { \ + FINISH(RET_C70A, 0); \ + } else if(addr == 0xc70d) { \ + FINISH(RET_C70D, 0); \ + } \ + } \ + if(wstat & (1 << (31 - BANK_IO2_BIT))) { \ + FCYCLES_ROUND; \ + fcycles_tmp1 = fcycles; \ + opcode = get_memory_io((addr), &fcycles_tmp1); \ + fcycles = fcycles_tmp1; \ + } else { \ + opcode = *ptr; \ + } \ + arg = get_remaining_operands(addr, opcode, psr, fplus_ptr);\ + arg_ptr = (byte *)&tmp_bytes; \ + arg_ptr[1] = arg; \ + arg_ptr[2] = arg >> 8; \ + arg_ptr[3] = arg >> 16; \ + } + +int +enter_engine(Engine_reg *engine_ptr) +{ + register byte *ptr; + byte *arg_ptr; + Pc_log *tmp_pc_ptr; + byte *stat; + word32 wstat; + word32 arg; + register word32 kpc; + register word32 acc; + register word32 xreg; + register word32 yreg; + word32 stack; + word32 dbank; + register word32 direct; + register word32 psr; + register word32 zero; + register word32 neg; + word32 getmem_tmp; + word32 save_addr; + word32 pull_tmp; + word32 tmp_bytes; + double fcycles; + Fplus *fplus_ptr; + double fplus_1; + double fplus_2; + double fplus_3; + double fplus_x_m1; + double fcycles_tmp1; + + word32 opcode; + register word32 addr; + word32 addr_latch; + word32 tmp1, tmp2; + + + tmp_pc_ptr = 0; + + kpc = engine_ptr->kpc; + acc = engine_ptr->acc; + xreg = engine_ptr->xreg; + yreg = engine_ptr->yreg; + stack = engine_ptr->stack; + dbank = engine_ptr->dbank; + direct = engine_ptr->direct; + psr = engine_ptr->psr; + fcycles = engine_ptr->fcycles; + fplus_ptr = engine_ptr->fplus_ptr; + zero = !(psr & 2); + neg = (psr >> 7) & 1; + + fplus_1 = fplus_ptr->plus_1; + fplus_2 = fplus_ptr->plus_2; + fplus_3 = fplus_ptr->plus_3; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + + g_ret1 = 0; + g_ret2 = 0; + +recalc_accsize: + if(psr & 0x20) { + while(fcycles <= g_fcycles_stop) { +#if 0 + if((neg & ~1) || (psr & (~0x1ff))) { + halt_printf("psr = %04x\n", psr); + } +#endif + + FETCH_OPCODE; + +#ifdef LOG_PC + LOG_PC_MACRO(); +#endif + + switch(opcode) { + default: + halt_printf("acc8 unk op: %02x\n", opcode); + arg = 9 +#define ACC8 +#include "defs_instr.h" + * 2; + break; +#include "8inst_c.h" + break; + } + } + } else { + while(fcycles <= g_fcycles_stop) { + FETCH_OPCODE; +#ifdef LOG_PC + LOG_PC_MACRO(); +#endif + + switch(opcode) { + default: + halt_printf("acc16 unk op: %02x\n", opcode); + arg = 9 +#undef ACC8 +#include "defs_instr.h" + * 2; + break; +#include "16inst_c.h" + break; + } + } + } + +finish: + engine_ptr->kpc = kpc; + engine_ptr->acc = acc; + engine_ptr->xreg = xreg; + engine_ptr->yreg = yreg; + engine_ptr->stack = stack; + engine_ptr->dbank = dbank; + engine_ptr->direct = direct; + engine_ptr->fcycles = fcycles; + + psr = psr & (~0x82); + psr |= (neg << 7); + psr |= ((!zero) << 1); + + engine_ptr->psr = psr; + + return (g_ret1 << 28) + g_ret2; +} + + +int g_engine_c_mode = 1; + +int defs_instr_start_8 = 0; +int defs_instr_end_8 = 0; +int defs_instr_start_16 = 0; +int defs_instr_end_16 = 0; +int op_routs_start = 0; +int op_routs_end = 0; + + diff --git a/src/engine_s.s b/src/engine_s.s new file mode 100644 index 0000000..c98ff9f --- /dev/null +++ b/src/engine_s.s @@ -0,0 +1,2491 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + + .data + .export rcsid_engine_s_s,data +rcsid_engine_s_s + .stringz "@(#)$KmKId: engine_s.s,v 1.155 2003-11-25 22:06:48-05 kentd Exp $" + + .code + + .level 1.1 + +#define INCLUDE_RCSID_S +#include "defs.h" +#undef INCLUDE_RCSID_S + +#define ASM + + +#if 0 +# define LOG_PC +# define ACCURATE_SLOW_MEM +# define DEBUG_TOOLBOX +#endif + + +/* +#define COUNT_GET_CALLS +*/ + +#if 0 +# define CHECK_SIZE_CONSISTENCY +#endif + + +#define STACK_ENGINE_SIZE 512 + +#define STACK_SAVE_CMP_INDEX_REG -64 +#define STACK_GET_MEM_B0_DIRECT_SAVELINK -68 +#define STACK_SAVE_ARG0 -72 +#define STACK_SAVE_INSTR -76 +#define STACK_SRC_BANK -80 +#define STACK_INST_TAB_PTR_DONT_USE_THIS -84 +#if 0 +#define STACK_BP_ARG0_SAVE -88 +#define STACK_BP_ARG1_SAVE -92 +#define STACK_BP_ARG2_SAVE -96 +#define STACK_BP_ARG3_SAVE -100 +#define STACK_BP_RP_SAVE -104 +#define STACK_BP_SCRATCH4_SAVE -108 +#endif + +#define STACK_GET_MEMORY_SAVE_LINK -112 +#define STACK_SET_MEMORY_SAVE_LINK -116 + +#define STACK_MEMORY16_SAVE1 -120 +#define STACK_MEMORY16_SAVE2 -124 +#define STACK_MEMORY16_SAVE3 -128 + +#define STACK_SAVE_CYCLES_WORD2 -132 /* Cycles = dword */ +#define STACK_SAVE_CYCLES -136 + +#define STACK_SET_MEMORY24_SAVE1 -140 +#define STACK_SET_MEMORY24_SAVE2 -144 +#define STACK_SET_MEMORY24_SAVE3 -148 + +#define STACK_GET_MEMORY24_SAVE1 -152 +#define STACK_GET_MEMORY24_SAVE2 -156 +#define STACK_GET_MEMORY24_SAVE3 -160 + +/* #define STACK_SAVE_INIT_CYCLES -164 */ +#define STACK_SAVE_DECIMAL16_A -168 +#define STACK_SAVE_DECIMAL16_B -172 +#define STACK_SAVE_INSTR_TMP1 -176 + +#define STACK_SAVE_DISPATCH_LINK -180 +#define STACK_SAVE_OP_LINK -184 +#define STACK_GET_MEMORY16_ADDR_LATCH -188 +#define STACK_GET_MEMORY24_ADDR_LATCH -192 + +#define STACK_GET_MEM_B0_DIRECT_ARG0 -200 +#define STACK_GET_MEM_B0_DIRECT_RET0 -204 +#define STACK_SAVE_PUSH16_LINK -208 +#define STACK_SAVE_PUSH16_ARG1 -212 + +#define STACK_SAVE_PULL16_LINK -216 +#define STACK_SAVE_PULL16_RET0 -220 +#define STACK_SAVE_PULL24_LINK -224 +#define STACK_SAVE_PULL24_RET0 -228 + +#define STACK_SAVE_COP_ARG0 -232 +#define STACK_SAVE_TMP_INST0 -236 +#define STACK_SAVE_TMP_INST -240 +#define STACK_SAVE_TMP_INST1 -244 +#define STACK_SAVE_DISP_PIECES_LINK -248 +#define STACK_SAVE_DISPATCH_SCRATCH1 -252 + +#if 0 +#define STACK_BP_SCRATCH2_SAVE -256 +#define STACK_BP_SCRATCH3_SAVE -260 +#endif + + + +#define CYCLES_PLUS_1 fadd,dbl fr_plus_1,fcycles,fcycles +#define CYCLES_PLUS_2 fadd,dbl fr_plus_2,fcycles,fcycles +#define CYCLES_PLUS_3 fadd,dbl fr_plus_3,fcycles,fcycles +#define CYCLES_PLUS_5 fadd,dbl fr_plus_3,fcycles,fcycles ! \ + fadd,dbl fr_plus_2,fcycles,fcycles + +#define CYCLES_MINUS_1 fsub,dbl fcycles,fr_plus_1,fcycles +#define CYCLES_MINUS_2 fsub,dbl fcycles,fr_plus_2,fcycles + +#define CYCLES_FINISH fadd,dbl fcycles_stop,fr_plus_1,fcycles + +#define FCYCLES_ROUND_1 fadd,dbl fcycles,fr_plus_x_m1,ftmp1 +#define FCYCLES_ROUND_2 fcnvfxt,dbl,dbl ftmp1,ftmp1 +#define FCYCLES_ROUND_3 fcnvxf,dbl,dbl ftmp1,fcycles + +/* HACK: INC_KPC* and DEC_KPC2 should avoid overflow into kbank! */ +#define INC_KPC_1 addi 1,kpc,kpc +#define INC_KPC_2 addi 2,kpc,kpc +#define INC_KPC_3 addi 3,kpc,kpc +#define INC_KPC_4 addi 4,kpc,kpc +#define DEC_KPC2 addi -2,kpc,kpc + +#define get_mem_b0_8 get_memory_asm +#define get_mem_b0_16 get_memory16_asm +#define get_mem_b0_24 get_memory24_asm + +#define get_mem_long_8 get_memory_asm +#define get_mem_long_16 get_memory16_asm +#define get_mem_long_24 get_memory24_asm + +#define set_mem_long_8 set_memory_asm +#define set_mem_long_16 set_memory16_asm + +#define set_mem_b0_8 set_memory_asm +#define set_mem_b0_16 set_memory16_asm +#define set_mem_b0_24 set_memory24_asm + + .code + .import halt_sim,data + .import g_fcycles_stop,data + .import g_irq_pending,data + .import g_wait_pending,data + .import g_rom_version,data + .import g_num_brk,data + .import g_num_cop,data + .import g_testing,data + + .import log_pc,code + .import toolbox_debug_c,code + + .import get_memory_io,code + + .import set_memory_io,code + .import set_memory16_pieces,code + .import set_memory24_pieces,code + +#define INCLUDE_RCSID_S +#include "op_routs.h" +#undef INCLUDE_RCSID_S + + .import do_break,code + .import do_cop,code + .import page_info_rd_wr,data + .import get_memory_calls,data + .import slow_mem_changed,data + .import g_cur_dcycs,data + .import g_last_vbl_dcycs,data + .import g_slow_memory_ptr,data + .import g_memory_ptr,data + .import g_dummy_memory1_ptr,data + .import g_rom_fc_ff_ptr,data + .import g_rom_cards_ptr,data + + .export fixed_memory_ptrs_init,code +fixed_memory_ptrs_init + LDC(slow_memory,arg0) + LDC(g_slow_memory_ptr,arg1) + stw arg0,(arg1) + + LDC(dummy_memory1,arg0) + LDC(g_dummy_memory1_ptr,arg1) + stw arg0,(arg1) + + LDC(rom_fc_ff,arg0) + LDC(g_rom_fc_ff_ptr,arg1) + stw arg0,(arg1) + + LDC(rom_cards,arg0) + LDC(g_rom_cards_ptr,arg1) + stw arg0,(arg1) + + bv 0(link) + nop + + .export get_itimer,code +get_itimer + bv 0(link) + mfctl %cr16,ret0 + + .export enter_asm,data +enter_asm + stwm page_info_ptr,STACK_ENGINE_SIZE(sp) + stw link,-STACK_ENGINE_SIZE+4(sp) + ldo -STACK_ENGINE_SIZE+16(sp),scratch2 + stw addr_latch,-STACK_ENGINE_SIZE+8(sp) + fstds,ma fcycles,8(scratch2) + fstds,ma fr_plus_1,8(scratch2) + fcpy,dbl 0,fcycles + fstds,ma fr_plus_2,8(scratch2) + fstds,ma fr_plus_3,8(scratch2) + fcpy,dbl 0,fr_plus_1 + fstds,ma fr_plus_x_m1,8(scratch2) + fstds,ma fcycles_stop,8(scratch2) + fcpy,dbl 0,fr_plus_2 + fstds,ma fcycles_last_dcycs,8(scratch2) + ldil l%g_cur_dcycs,scratch2 + + ldil l%g_last_vbl_dcycs,scratch3 + fcpy,dbl 0,fr_plus_3 + ldo r%g_cur_dcycs(scratch2),scratch2 + fcpy,dbl 0,fr_plus_x_m1 + ldo r%g_last_vbl_dcycs(scratch3),scratch3 + fldds 0(scratch2),ftmp1 + ldil l%page_info_rd_wr,page_info_ptr + fldds 0(scratch3),fcycles_last_dcycs + fcpy,dbl 0,fcycles_stop + ldo r%page_info_rd_wr(page_info_ptr),page_info_ptr + bv 0(scratch1) + fsub,dbl ftmp1,fcycles_last_dcycs,fcycles + + + .export leave_asm,data +leave_asm + ldw -STACK_ENGINE_SIZE+4(sp),link + ldo -STACK_ENGINE_SIZE+16(sp),scratch2 + ldw -STACK_ENGINE_SIZE+8(sp),addr_latch + fldds,ma 8(scratch2),fcycles + fldds,ma 8(scratch2),fr_plus_1 + fldds,ma 8(scratch2),fr_plus_2 + fldds,ma 8(scratch2),fr_plus_3 + fldds,ma 8(scratch2),fr_plus_x_m1 + fldds,ma 8(scratch2),fcycles_stop + fldds,ma 8(scratch2),fcycles_last_dcycs + + bv (link) + ldwm -STACK_ENGINE_SIZE(sp),page_info_ptr + + + .align 8 + .export get_memory_c +get_memory_c +; arg0 = addr +; arg1 = cycles + bl enter_asm,scratch1 + nop + bl get_memory_asm,link + nop + b leave_asm + nop + + .export get_memory16_c +get_memory16_c +; arg0 = addr +; arg1 = cycles + bl enter_asm,scratch1 + nop + bl get_memory16_asm,link + nop + b leave_asm + nop + + .export get_memory24_c +get_memory24_c +; arg0 = addr +; arg1 = cycles + bl enter_asm,scratch1 + nop + bl get_memory24_asm,link + nop + b leave_asm + nop + +#define GET_MEM8(upper16,lower8,ret0) \ + extru arg0,23,16,arg3 ! \ + CYCLES_PLUS_1 ! \ + ldwx,s arg3(page_info_ptr),scratch3 ! \ + copy arg0,addr_latch ! \ + copy scratch3,scratch2 ! \ + dep arg0,31,8,scratch3 ! \ + extru,= scratch2,BANK_IO_BIT,1,0 ! \ + bl,n get_memory_iocheck_stub_asm,link ! \ + ldb (scratch3),ret0 + + .align 32 + + .export get_memory_asm +get_memory_asm +; arg0 = addr + extru arg0,23,16,arg3 + copy arg0,addr_latch + + ldwx,s arg3(page_info_ptr),scratch2 + CYCLES_PLUS_1 + bb,<,n scratch2,BANK_IO_BIT,get_memory_iocheck_stub_asm + dep arg0,31,8,scratch2 + bv 0(link) + ldb (scratch2),ret0 + + + .align 8 + + .export get_memory16_asm +get_memory16_asm +; arg0 = addr + ldi 0xff,scratch3 + extru arg0,23,16,arg3 + + and scratch3,arg0,scratch4 + ldwx,s arg3(page_info_ptr),scratch2 + copy arg0,addr_latch + comb,= scratch4,scratch3,get_memory16_pieces_stub_asm + and scratch2,scratch3,scratch3 + comb,<> 0,scratch3,get_memory16_pieces_stub_asm + dep arg0,31,8,scratch2 + ldb (scratch2),ret0 + CYCLES_PLUS_2 + ldb 1(scratch2),scratch1 + bv 0(link) + dep scratch1,23,8,ret0 + + .align 8 + + .export get_memory24_asm +get_memory24_asm +; arg0 = addr + ldi 0xfe,scratch3 + extru arg0,23,16,arg3 + + and scratch3,arg0,scratch4 + ldwx,s arg3(page_info_ptr),scratch2 + copy arg0,addr_latch + comb,= scratch4,scratch3,get_memory24_pieces_stub_asm + extru scratch2,31,8,scratch3 + comb,<> 0,scratch3,get_memory24_pieces_stub_asm + dep arg0,31,8,scratch2 + ldb (scratch2),ret0 + ldb 1(scratch2),scratch1 + CYCLES_PLUS_3 + ldb 2(scratch2),scratch2 + dep scratch1,23,8,ret0 + bv 0(link) + dep scratch2,15,8,ret0 + + + .align 0x20 + .export get_memory_iocheck_stub_asm,code +get_memory_iocheck_stub_asm + extru,= scratch2,BANK_BREAK_BIT,1,0 + bl check_breakpoints_asm,scratch4 + stw link,STACK_GET_MEMORY_SAVE_LINK(sp) + bb,< scratch2,BANK_IO2_BIT,get_memory_io_stub_asm + dep arg0,31,8,scratch2 + bv 0(link) + ldb (scratch2),ret0 + + .export get_memory_io_stub_asm +get_memory_io_stub_asm + FCYCLES_ROUND_1 + ldo STACK_SAVE_CYCLES(sp),arg1 + FCYCLES_ROUND_2 + FCYCLES_ROUND_3 + bl get_memory_io,link + fstds fcycles,(arg1) + + ldw STACK_GET_MEMORY_SAVE_LINK(sp),link + ldo STACK_SAVE_CYCLES(sp),arg1 + bv (link) + fldds (arg1),fcycles + + + + .export get_memory16_pieces_stub_asm,code +get_memory16_pieces_stub_asm + stw addr_latch,STACK_GET_MEMORY16_ADDR_LATCH(sp) + addi 1,arg0,scratch1 + stw link,STACK_MEMORY16_SAVE2(sp) + bl get_memory_asm,link + stw scratch1,STACK_MEMORY16_SAVE1(sp) + + stw ret0,STACK_MEMORY16_SAVE3(sp) + bl get_memory_asm,link + ldw STACK_MEMORY16_SAVE1(sp),arg0 + + ldw STACK_MEMORY16_SAVE2(sp),link + copy ret0,scratch1 + ldw STACK_MEMORY16_SAVE3(sp),ret0 + ldw STACK_GET_MEMORY16_ADDR_LATCH(sp),addr_latch + bv (link) + dep scratch1,23,8,ret0 + + + .export get_memory24_pieces_stub_asm,code +get_memory24_pieces_stub_asm + stw addr_latch,STACK_GET_MEMORY16_ADDR_LATCH(sp) + addi 1,arg0,scratch1 + stw link,STACK_GET_MEMORY24_SAVE2(sp) + bl get_memory_asm,link + stw scratch1,STACK_GET_MEMORY24_SAVE1(sp) + + stw ret0,STACK_GET_MEMORY24_SAVE3(sp) + bl get_memory_asm,link + ldw STACK_GET_MEMORY24_SAVE1(sp),arg0 + + ldw STACK_GET_MEMORY24_SAVE1(sp),arg0 + stb ret0,STACK_GET_MEMORY24_SAVE3+2(sp) + bl get_memory_asm,link + addi 1,arg0,arg0 + + ldw STACK_GET_MEMORY24_SAVE2(sp),link + copy ret0,scratch1 + ldw STACK_GET_MEMORY24_SAVE3(sp),ret0 + ldw STACK_GET_MEMORY16_ADDR_LATCH(sp),addr_latch + bv (link) + dep scratch1,15,8,ret0 + + + + +; C callable routine to wrap around set_memory_asm + .export set_memory_c +set_memory_c +;arg0 = addr +;arg1 = val +;arg2 = cycles + bl enter_asm,scratch1 + nop + bl set_memory_asm,link + nop + b leave_asm + nop + + + .export set_memory16_c +set_memory16_c +;arg0 = addr +;arg1 = val +;arg2 = cycles + bl enter_asm,scratch1 + nop + bl set_memory16_asm,link + nop + b leave_asm + nop + + .export set_memory24_c +set_memory24_c +;arg0 = addr +;arg1 = val +;arg2 = cycles + bl enter_asm,scratch1 + nop + bl set_memory24_asm,link + nop + b leave_asm + nop + + + .align 32 + + .export set_memory_asm +set_memory_asm +; arg0 = addr +; arg1 = val + extru arg0,23,16,arg3 + addil l%PAGE_INFO_WR_OFFSET,arg3 + CYCLES_PLUS_1 + ldwx,s r1(page_info_ptr),scratch2 + ldi 0xff,scratch3 + and scratch2,scratch3,scratch3 + dep arg0,31,8,scratch2 + comib,<>,n 0,scratch3,set_memory_special_case +set_memory_cont_asm + bv 0(link) + stb arg1,(scratch2) + + + .export set_memory_special_case +set_memory_special_case + extru,= scratch3,BANK_BREAK_BIT,1,0 + bl check_breakpoints_asm,scratch4 + extru arg1,31,8,arg1 + +set_memory_special_case2 + bb,< scratch3,BANK_IO2_BIT,set_memory_io_stub_asm + ldil l%slow_memory,scratch4 + bb,< scratch3,BANK_SHADOW_BIT,set_memory_shadow1_asm + extru arg0,31,16,arg3 + bb,< scratch3,BANK_SHADOW2_BIT,set_memory_shadow2_asm + nop + bb,< scratch3,BANK_BREAK_BIT,set_memory_cont_asm + nop + break + + +set_memory_shadow1_asm +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_1 +#endif + add arg3,scratch4,scratch4 + extru arg3,31-SHIFT_PER_CHANGE,5,scratch1 + ldb r%slow_memory(scratch4),arg2 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_2 +#endif + mtctl scratch1,cr11 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_3 +#endif + comclr,<> arg2,arg1,0 + bv 0(link) + stb arg1,(scratch2) + zvdepi 1,1,arg2 + extru arg3,31-CHANGE_SHIFT,16-CHANGE_SHIFT,scratch2 + ldil l%slow_mem_changed,scratch1 + sh2add scratch2,scratch1,scratch1 + ldw r%slow_mem_changed(scratch1),scratch3 + stb arg1,r%slow_memory(scratch4) + or arg2,scratch3,scratch3 + bv 0(link) + stw scratch3,r%slow_mem_changed(scratch1) + +set_memory_shadow2_asm + depi 1,15,1,arg3 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_1 +#endif + add arg3,scratch4,scratch4 + extru arg3,31-SHIFT_PER_CHANGE,5,scratch1 + ldb r%slow_memory(scratch4),arg2 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_2 +#endif + mtctl scratch1,cr11 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_3 +#endif + comclr,<> arg2,arg1,0 + bv 0(link) + stb arg1,(scratch2) + zvdepi 1,1,arg2 + extru arg3,31-CHANGE_SHIFT,16-CHANGE_SHIFT,scratch2 + ldil l%slow_mem_changed,scratch1 + sh2add scratch2,scratch1,scratch1 + ldw r%slow_mem_changed(scratch1),scratch3 + stb arg1,r%slow_memory(scratch4) + or arg2,scratch3,scratch3 + bv 0(link) + stw scratch3,r%slow_mem_changed(scratch1) + + +set_memory_io_stub_asm + FCYCLES_ROUND_1 + ldo STACK_SAVE_CYCLES(sp),arg2 + FCYCLES_ROUND_2 + stw link,STACK_SET_MEMORY_SAVE_LINK(sp) + FCYCLES_ROUND_3 + bl set_memory_io,link + fstds fcycles,(arg2) + + ldw STACK_SET_MEMORY_SAVE_LINK(sp),link + ldo STACK_SAVE_CYCLES(sp),arg2 + bv (link) + fldds (arg2),fcycles + + .align 8 + .export set_memory16_asm +set_memory16_asm +; arg0 = addr +; arg1 = val + extru arg0,23,16,arg3 + + addil l%PAGE_INFO_WR_OFFSET,arg3 + extrs arg0,31,8,scratch4 + ldwx,s r1(page_info_ptr),scratch2 + ldi 0xff,scratch3 + and scratch3,scratch2,scratch3 + dep arg0,31,8,scratch2 + comib,=,n -1,scratch4,set_memory16_pieces_stub_asm + comib,<>,n 0,scratch3,set_memory16_special_case +set_memory16_cont_asm + stb arg1,0(scratch2) + CYCLES_PLUS_2 + extru arg1,23,8,arg3 + bv 0(link) + stb arg3,1(scratch2) + + + .align 8 +set_memory16_shadow1_asm + CYCLES_PLUS_2 + copy arg1,arg2 + extru arg1,23,8,arg1 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_1 +#endif + add arg3,scratch4,scratch4 + dep arg2,23,8,arg1 + extru arg3,31-SHIFT_PER_CHANGE,5,scratch1 + ldh r%slow_memory(scratch4),arg2 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_2 +#endif + mtctl scratch1,cr11 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_3 +#endif + comclr,<> arg2,arg1,0 ;return if arg2 == arg1 + bv 0(link) + sth arg1,(scratch2) + zvdepi 1,1,arg2 + extru arg3,31-CHANGE_SHIFT,16-CHANGE_SHIFT,scratch2 + ldil l%slow_mem_changed,scratch1 + sh2add scratch2,scratch1,scratch1 + ldw r%slow_mem_changed(scratch1),scratch3 + sth arg1,r%slow_memory(scratch4) + or arg2,scratch3,scratch3 + bv 0(link) + stw scratch3,r%slow_mem_changed(scratch1) + + .align 8 +set_memory16_shadow2_asm + CYCLES_PLUS_2 + copy arg1,arg2 + extru arg1,23,8,arg1 + depi 1,15,1,arg3 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_1 +#endif + dep arg2,23,8,arg1 + add arg3,scratch4,scratch4 + extru arg3,31-SHIFT_PER_CHANGE,5,scratch1 + ldh r%slow_memory(scratch4),arg2 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_2 +#endif + mtctl scratch1,cr11 +#ifdef ACCURATE_SLOW_MEM + FCYCLES_ROUND_3 +#endif + comclr,<> arg2,arg1,0 + bv 0(link) + sth arg1,(scratch2) + zvdepi 1,1,arg2 + extru arg3,31-CHANGE_SHIFT,16-CHANGE_SHIFT,scratch2 + ldil l%slow_mem_changed,scratch1 + sh2add scratch2,scratch1,scratch1 + ldw r%slow_mem_changed(scratch1),scratch3 + sth arg1,r%slow_memory(scratch4) + or arg2,scratch3,scratch3 + bv 0(link) + stw scratch3,r%slow_mem_changed(scratch1) + + + .align 8 +set_memory16_special_case + extru,= scratch3,BANK_BREAK_BIT,1,0 + bl check_breakpoints_asm,scratch4 + extru arg1,31,16,arg1 + +set_memory16_special_case2 + bb,< scratch3,BANK_IO2_BIT,set_memory16_pieces_stub_asm + ldil l%slow_memory,scratch4 + +; if not halfword aligned, go through pieces_stub_asm + bb,<,n arg0,31,set_memory16_pieces_stub_asm + bb,< scratch3,BANK_SHADOW2_BIT,set_memory16_shadow2_asm + extru arg0,31,16,arg3 + bb,< scratch3,BANK_SHADOW_BIT,set_memory16_shadow1_asm + nop + bb,< scratch3,BANK_BREAK_BIT,set_memory16_cont_asm + nop + break + + .align 8 +set_memory16_pieces_stub_asm + addi 1,arg0,scratch1 + stw link,STACK_MEMORY16_SAVE3(sp) + extru arg1,23,8,scratch2 + stw scratch1,STACK_MEMORY16_SAVE1(sp) + bl set_memory_asm,link + stw scratch2,STACK_MEMORY16_SAVE2(sp) + + ldw STACK_MEMORY16_SAVE1(sp),arg0 + ldw STACK_MEMORY16_SAVE2(sp),arg1 + b set_memory_asm + ldw STACK_MEMORY16_SAVE3(sp),link + + + .align 8 + .export set_memory24_asm +set_memory24_asm +; arg0 = addr +; arg1 = val + extru arg0,23,16,arg3 + + addil l%PAGE_INFO_WR_OFFSET,arg3 + extrs arg0,30,7,scratch4 + ldwx,s r1(page_info_ptr),scratch2 + ldi 0xff,scratch3 + and scratch3,scratch2,scratch3 + dep arg0,31,8,scratch2 + comib,=,n -1,scratch4,set_memory24_pieces_stub_asm + comib,<>,n 0,scratch3,set_memory24_pieces_stub_asm + stb arg1,0(scratch2) + extru arg1,23,8,arg3 + CYCLES_PLUS_3 + stb arg3,1(scratch2) + extru arg1,15,8,arg3 + bv 0(link) + stb arg3,2(scratch2) + +set_memory24_pieces_stub_asm + addi 1,arg0,scratch1 + stw link,STACK_SET_MEMORY24_SAVE3(sp) + extru arg1,23,16,scratch2 + stw scratch1,STACK_SET_MEMORY24_SAVE1(sp) + bl set_memory_asm,link + stw scratch2,STACK_SET_MEMORY24_SAVE2(sp) + + ldw STACK_SET_MEMORY24_SAVE1(sp),arg0 + bl set_memory_asm,link + ldw STACK_SET_MEMORY24_SAVE2(sp),arg1 + + ldw STACK_SET_MEMORY24_SAVE1(sp),arg0 + ldw STACK_SET_MEMORY24_SAVE3(sp),link + addi 1,arg0,arg0 + b set_memory_asm + ldb STACK_SET_MEMORY24_SAVE2+2(sp),arg1 + + + + + + .import g_num_breakpoints,data + .import g_breakpts,data + + .align 8 + .export check_breakpoints_asm,code +check_breakpoints_asm +; can't use arg0-arg3. don't use scratch2,scratch3 +; scratch4: return link +; + ldil l%g_num_breakpoints,scratch1 + ldil l%g_breakpts,ret0 + ldw r%g_num_breakpoints(scratch1),r1 + ldo r%g_breakpts(ret0),ret0 + addi,>= -1,r1,r1 + bv,n 0(scratch4) + ldwx,s r1(ret0),scratch1 +check_breakpoints_loop_asm + comb,=,n scratch1,arg0,check_breakpoints_hit + addib,>=,n -1,r1,check_breakpoints_loop_asm + ldwx,s r1(ret0),scratch1 + + bv 0(scratch4) + nop + + .export check_breakpoints_hit,code +check_breakpoints_hit + LDC(halt_sim,scratch1) + ldw (scratch1),r1 + ldil l%g_fcycles_stop,ret0 + depi 1,31,1,r1 + stw 0,r%g_fcycles_stop(ret0) + stw 0,r%g_fcycles_stop+4(ret0) + bv 0(scratch4) + stw r1,(scratch1) + nop + nop + nop + + + + .align 8 + .export set_mem_yreg +set_mem_yreg +; arg0 = addr to write + extru,= psr,27,1,0 ;null branch if 16 bit + b set_memory_asm + copy yreg,arg1 +;if get here, 16 bit yreg + b,n set_memory16_asm + nop + + + .align 8 + .export set_mem_xreg +set_mem_xreg +; arg0 = addr to write + extru,= psr,27,1,0 ;null branch if 16 bit + b set_memory_asm + copy xreg,arg1 +;if get here, 16 bit xreg + b,n set_memory16_asm + nop + + + + .export get_memory_outofrange,code +get_memory_outofrange + break + + +get_mem_b0_16_stub + b get_mem_b0_16 + nop + + .align 8 +get_mem_b0_direct_page_16 +; get 2 bytes for direct-page fetch. +; arg0 = addr; +; if emul and dl = 0, then stick dh in +; into high bytes. +; if emul, grab + 1 byte from dh page also. +; if not emul, just call get_mem_b0 + ldi 0xff,scratch2 + extru,<> psr,23,1,0 ;null next if emul bit set + b get_mem_b0_16 + extru direct,23,8,scratch1 + and arg0,scratch2,scratch3 + extru,<> direct,31,8,0 ;null if direct not page aligned + dep scratch1,23,24,arg0 ;..done only if direct is page aligned + comb,<> scratch3,scratch2,get_mem_b0_16_stub + stw link,STACK_GET_MEM_B0_DIRECT_SAVELINK(sp) +; we're at 0x??ff, so next byte needs to come from 0x??00. + bl get_mem_b0_8,link + stw arg0,STACK_GET_MEM_B0_DIRECT_ARG0(sp) +; now, get next byte + ldw STACK_GET_MEM_B0_DIRECT_ARG0(sp),arg0 + extru direct,23,8,scratch1 + stw ret0,STACK_GET_MEM_B0_DIRECT_RET0(sp) + addi 1,arg0,arg0 + extru,<> direct,31,8,0 ;null if direct not page aligned + dep scratch1,23,24,arg0 ;..done only if direct is page aligned + bl get_mem_b0_8,link + nop + +; and return + copy ret0,scratch2 + ldw STACK_GET_MEM_B0_DIRECT_SAVELINK(sp),scratch1 + ldb STACK_GET_MEM_B0_DIRECT_RET0+3(sp),ret0 + bv (scratch1) + dep scratch2,23,8,ret0 + + + +push_8 + copy arg0,arg1 + copy stack,arg0 + addi -1,stack,stack + extru,= psr,23,1,0 ;emul mode? + depi 1,23,24,stack + b set_mem_b0_8 + extru stack,31,16,stack + +pull_8 + addi 1,stack,stack + extru,= psr,23,1,0 + depi 1,23,24,stack + extru stack,31,16,stack + b get_mem_b0_8 + copy stack,arg0 + +push_16 + copy arg0,arg1 + bb,>= psr,23,push_16_native + extru stack,30,7,scratch1 + +; push_16_emul + addi -2,stack,stack + comib,= 0,scratch1,push_16_emul_page + addi 1,stack,arg0 ;we know we are not at end of page + b set_mem_b0_16 + depi 1,23,24,stack + + +push_16_emul_page + stw link,STACK_SAVE_PUSH16_LINK(sp) + addi 1,arg0,arg0 + stw arg1,STACK_SAVE_PUSH16_ARG1(sp) + depi 1,23,24,arg0 + bl set_mem_b0_8,link + extru arg1,23,8,arg1 +; and do next push + addi 1,stack,arg0 + depi 1,23,24,stack + ldw STACK_SAVE_PUSH16_LINK(sp),link + ldb STACK_SAVE_PUSH16_ARG1+3(sp),arg1 + b set_mem_b0_8 + depi 1,23,24,arg0 + +push_16_native +; here, we're a native push_16 + addi -2,stack,stack + comib,= 0,scratch1,push_16_nat_page + addi 1,stack,arg0 ;we know we are not at end of page + b set_mem_b0_16 + extru stack,31,16,stack + + +push_16_nat_page + stw link,STACK_SAVE_PUSH16_LINK(sp) + addi 1,arg0,arg0 + stw arg1,STACK_SAVE_PUSH16_ARG1(sp) + extru arg0,31,16,arg0 + bl set_mem_b0_8,link + extru arg1,23,8,arg1 +; and do next push + addi 1,stack,arg0 + extru stack,31,16,stack + ldw STACK_SAVE_PUSH16_LINK(sp),link + ldb STACK_SAVE_PUSH16_ARG1+3(sp),arg1 + b set_mem_b0_8 + extru arg0,31,16,arg0 + +push_16_unsafe + copy arg0,arg1 + addi -1,stack,arg0 + addi -2,stack,stack + extru,= psr,23,1,0 + depi 1,23,24,stack + extru arg0,31,16,arg0 + b set_mem_b0_16 + extru stack,31,16,stack + +push_24_unsafe + copy arg0,arg1 + addi -2,stack,arg0 + addi -3,stack,stack + extru,= psr,23,1,0 + depi 1,23,24,stack + extru arg0,31,16,arg0 + b set_mem_b0_24 + extru stack,31,16,stack + +pull_16_unsafe + addi 1,stack,stack + extru,= psr,23,1,0 + depi 1,23,24,stack + extru stack,31,16,arg0 + addi 1,stack,stack + extru,= psr,23,1,0 + depi 1,23,24,stack + b get_mem_b0_16 + extru stack,31,16,stack + + .align 8 +pull_16 + extrs stack,29,6,scratch1 + bb,< psr,23,pull_16_emul + addi 1,stack,arg0 + comib,= -1,scratch1,pull_16_nat_page + addi 2,stack,stack +; if we get here, native & not near page cross + extru arg0,31,16,arg0 + b get_mem_b0_16 + extru stack,31,16,stack + +pull_16_emul + comib,= -1,scratch1,pull_16_emul_page + addi 2,stack,stack +; if get here, emul & not near page cross + b get_mem_b0_16 + depi 1,23,24,stack + +pull_16_nat_page + stw link,STACK_SAVE_PULL16_LINK(sp) + bl get_mem_b0_8,link + extru arg0,31,16,arg0 +; got first byte + stw ret0,STACK_SAVE_PULL16_RET0(sp) + extru stack,31,16,stack + bl get_mem_b0_8,link + copy stack,arg0 +; got second byte + ldw STACK_SAVE_PULL16_LINK(sp),link + copy ret0,scratch1 + ldb STACK_SAVE_PULL16_RET0+3(sp),ret0 + bv 0(link) + dep scratch1,23,8,ret0 + +pull_16_emul_page + stw link,STACK_SAVE_PULL16_LINK(sp) + bl get_mem_b0_8,link + depi 1,23,24,arg0 +; got first byte + stw ret0,STACK_SAVE_PULL16_RET0(sp) + depi 1,23,24,stack + bl get_mem_b0_8,link + copy stack,arg0 +; got second byte + ldw STACK_SAVE_PULL16_LINK(sp),link + copy ret0,scratch1 + ldb STACK_SAVE_PULL16_RET0+3(sp),ret0 + bv 0(link) + dep scratch1,23,8,ret0 + + .export pull_24,code +pull_24 + extrs stack,29,6,scratch1 + bb,< psr,23,pull_24_emul + addi 1,stack,arg0 + comib,= -1,scratch1,pull_24_nat_page + addi 3,stack,stack +; if we get here, native & not near page cross, go for it + extru arg0,31,16,arg0 + b get_mem_b0_24 + extru stack,31,16,stack + +pull_24_emul + depi 1,23,24,arg0 + comib,= -1,scratch1,pull_24_emul_page + addi 3,stack,stack +; if we get here, emul & not near page cross + b get_mem_b0_24 + depi 1,23,24,stack + +pull_24_nat_page + stw link,STACK_SAVE_PULL24_LINK(sp) + bl get_mem_b0_8,link + extru arg0,31,16,arg0 +; got first byte + stw ret0,STACK_SAVE_PULL24_RET0(sp) + addi -1,stack,arg0 + extru stack,31,16,stack + bl get_mem_b0_8,link + extru arg0,31,16,arg0 +; got second byte + stb ret0,STACK_SAVE_PULL24_RET0+2(sp) + bl get_mem_b0_8,link + copy stack,arg0 +; got all bytes + ldw STACK_SAVE_PULL24_LINK(sp),link + copy ret0,scratch1 + ldw STACK_SAVE_PULL24_RET0(sp),ret0 + bv (link) + dep scratch1,15,8,ret0 + +pull_24_emul_page + stw link,STACK_SAVE_PULL24_LINK(sp) + bl get_mem_b0_8,link + nop +; got first byte + addi -1,stack,arg0 + stw ret0,STACK_SAVE_PULL24_RET0(sp) + depi 1,23,24,stack + bl get_mem_b0_8,link + depi 1,23,24,arg0 +; got second byte + stb ret0,STACK_SAVE_PULL24_RET0+2(sp) + bl get_mem_b0_8,link + copy stack,arg0 +; got all bytes + ldw STACK_SAVE_PULL24_LINK(sp),link + copy ret0,scratch1 + ldw STACK_SAVE_PULL24_RET0(sp),ret0 + bv (link) + dep scratch1,15,8,ret0 + +update_system_state_and_change_kbank +; kbank already changed..do nothing + +update_system_state +; psr is new psw state +; arg0 is old in bits 31 and 30 + ldi 0x30,scratch1 + extru,= psr,23,1,0 + depi 3,27,2,psr + and psr,scratch1,scratch1 + extru,= psr,23,1,0 + depi 1,23,24,stack + dep arg0,29,2,scratch1 + blr scratch1,0 + addit,>= -0x3d,scratch1,0 +; 0000: no change + b update_sys9 + nop ! nop ! nop + nop ! nop ! nop ! nop +; 0001: x from 1->0 + b update_sys9 + ldi 2,scratch1 + nop ! nop + nop ! nop ! nop ! nop +; 0010: m from 1->0 + b resize_acc_to16 + ldi 0,ret0 + nop ! nop + nop ! nop ! nop ! nop +; 0011: m,x from 1->0 + b resize_acc_to16 + ldi 0,ret0 + nop ! nop + nop ! nop ! nop ! nop +; 0100: x from 0->1 + depi 0,23,24,yreg + b update_sys9 + depi 0,23,24,xreg + nop + nop ! nop ! nop ! nop +; 0101: no change + b update_sys9 + nop ! nop ! nop + nop ! nop ! nop ! nop +; 0110: x from 0->1, m from 1->0 + depi 0,23,24,yreg + ldi 0,ret0 + b resize_acc_to16 + depi 0,23,24,xreg + nop ! nop ! nop ! nop +; 0111: m from 1->0 + b resize_acc_to16 + ldi 0,ret0 + nop ! nop + nop ! nop ! nop ! nop +; 1000: m from 0->1 + b resize_acc_to8 + ldi 0,ret0 + nop ! nop + nop ! nop ! nop ! nop +; 1001: m from 0->1, x from 1->0 + b resize_acc_to8 + ldi 0,ret0 + nop ! nop + nop ! nop ! nop ! nop +; 1010: no change + b update_sys9 + nop ! nop ! nop + nop ! nop ! nop ! nop +; 1011: x from 1->0 + b update_sys9 + nop ! nop ! nop + nop ! nop ! nop ! nop +; 1100: m,x from 0->1 + depi 0,23,24,yreg + ldi 0,ret0 + b resize_acc_to8 + depi 0,23,24,xreg + nop ! nop ! nop ! nop +; 1101: m from 0->1 + b resize_acc_to8 + ldi 0,ret0 + nop ! nop + nop ! nop ! nop ! nop +; 1110: x from 0->1 + depi 0,23,24,yreg + ldi 0,ret0 + b update_sys9 + depi 0,23,24,xreg + nop ! nop ! nop ! nop +; 1111: no change + b update_sys9 + nop ! nop ! nop + nop ! nop ! nop ! nop +; 10000 + break + + + .export get_yreg_from_mem,code +get_yreg_from_mem +; arg0 = addr to read from, write into yreg + bb,>=,n psr,27,get_yreg_from_mem16 + bl get_mem_b0_8,link + extru arg0,31,24,arg0 + + extru ret0,31,8,zero + extru ret0,24,1,neg + b dispatch + copy zero,yreg + + .export get_yreg_from_mem16,code +get_yreg_from_mem16 + bl get_mem_b0_16,link + extru arg0,31,24,arg0 + + extru ret0,31,16,zero + extru ret0,16,1,neg + b dispatch + copy zero,yreg + + + .export get_xreg_from_mem,code +get_xreg_from_mem +; arg0 = addr to read from, write into xreg + bb,>=,n psr,27,get_xreg_from_mem16 + bl get_mem_b0_8,link + extru arg0,31,24,arg0 + + extru ret0,31,8,zero + extru ret0,24,1,neg + b dispatch + copy zero,xreg + + .export get_xreg_from_mem16,code +get_xreg_from_mem16 + bl get_mem_b0_16,link + extru arg0,31,24,arg0 + + extru ret0,31,16,zero + extru ret0,16,1,neg + b dispatch + copy zero,xreg + + + + + .export enter_engine,code +enter_engine +; load up regs with struct vals + .proc + .callinfo frame=STACK_ENGINE_SIZE,caller,save_rp,entry_gr=18,entry_fr=19 + .enter + + ldw ENGINE_FPLUS_PTR(arg0),scratch1 ;fplus ptr + fldds ENGINE_FCYCLES(arg0),fcycles + + ldil l%g_fcycles_stop,fcycles_stop_ptr + ldw ENGINE_REG_ACC(arg0),acc + ldo r%g_fcycles_stop(fcycles_stop_ptr),fcycles_stop_ptr + fldds FPLUS_PLUS_1(scratch1),fr_plus_1 + ldo FPLUS_PLUS_3(scratch1),ret0 + fldds FPLUS_PLUS_2(scratch1),fr_plus_2 + ldil l%g_last_vbl_dcycs,ret1 + fldds FPLUS_PLUS_3-FPLUS_PLUS_3(ret0),fr_plus_3 + ldo r%g_last_vbl_dcycs(ret1),ret1 + fldds FPLUS_PLUS_X_M1-FPLUS_PLUS_3(ret0),fr_plus_x_m1 + fldds 0(ret1),fcycles_last_dcycs + ldil l%table8,ret0 + ldw ENGINE_REG_XREG(arg0),xreg + ldil l%table16,inst_tab_ptr + ldw ENGINE_REG_YREG(arg0),yreg + ldo r%table8(ret0),ret0 + ldw ENGINE_REG_STACK(arg0),stack + ldo r%table16(inst_tab_ptr),inst_tab_ptr + ldw ENGINE_REG_PSR(arg0),psr + ldi 0,zero + ldw ENGINE_REG_DBANK(arg0),dbank + ldil l%page_info_rd_wr,page_info_ptr + ldw ENGINE_REG_DIRECT(arg0),direct + extru,= psr,26,1,0 ;nullify if acc size = 0 == 16bit + copy ret0,inst_tab_ptr + ldw ENGINE_REG_KPC(arg0),kpc + + ldo r%page_info_rd_wr(page_info_ptr),page_info_ptr + extru,<> psr,30,1,0 + ldi 1,zero + extru psr,24,1,neg + stw arg0,STACK_SAVE_ARG0(sp) + ldi 0xfd,const_fd + b dispatch + ldi 0,scratch1 + + .export resize_acc_to8,code +resize_acc_to8 + ldil l%table8,inst_tab_ptr + extru psr,27,1,scratch1 ;size of x + b update_sys9 + ldo r%table8(inst_tab_ptr),inst_tab_ptr + + .export resize_acc_to16,code +resize_acc_to16 + ldil l%table16,inst_tab_ptr + extru psr,27,1,scratch1 + b update_sys9 + ldo r%table16(inst_tab_ptr),inst_tab_ptr + + + +dispatch_done_cycles_mismatch + ldi -1,ret0 + b dispatch_done + nop + + + + .export dispatch_done +dispatch_done + bl refresh_engine_struct,link + ldw STACK_SAVE_ARG0(sp),arg0 + .leave + .procend + +refresh_engine_struct +; warning--this routine must not change arg1, arg2, arg3, or ret0 +; can only change scratch1 + + comiclr,<> 0,zero,scratch1 + ldi 1,scratch1 + dep neg,24,1,psr + dep scratch1,30,1,psr + stw acc,ENGINE_REG_ACC(arg0) + stw xreg,ENGINE_REG_XREG(arg0) + stw yreg,ENGINE_REG_YREG(arg0) + stw stack,ENGINE_REG_STACK(arg0) + stw dbank,ENGINE_REG_DBANK(arg0) + stw direct,ENGINE_REG_DIRECT(arg0) + stw psr,ENGINE_REG_PSR(arg0) + stw kpc,ENGINE_REG_KPC(arg0) + bv 0(link) + fstds fcycles,ENGINE_FCYCLES(arg0) + + .export check_irqs_pending,code +update_sys9 +check_irqs_pending +; if any g_irq_pending, return RET_IRQ + ldil l%g_irq_pending,scratch1 + ldw r%g_irq_pending(scratch1),scratch2 + bb,<,n psr,29,dispatch + comib,= 0,scratch2,dispatch + zdepi RET_IRQ,3,4,ret0 + b,n dispatch_done + nop + + .export clr_halt_act + .export set_halt_act +clr_halt_act + LDC(halt_sim,scratch1) + bv 0(link) + stw 0,(scratch1) + +set_halt_act + LDC(halt_sim,scratch1) + ldw (scratch1),scratch2 + ldil l%g_fcycles_stop,scratch3 + stw 0,r%g_fcycles_stop(scratch3) + or scratch2,arg0,arg0 + stw 0,r%g_fcycles_stop+4(scratch3) + bv 0(link) + stw arg0,(scratch1) + + + .align 32 + .export dispatch_fast,code +dispatch_fast +; instr is the instr to fetch +#ifdef LOG_PC + b dispatch + nop +#endif + fldds 0(fcycles_stop_ptr),fcycles_stop + extru kpc,23,16,arg2 + + extru kpc,31,8,scratch4 + ldwx,s arg2(page_info_ptr),scratch2 + + ldwx,s instr(inst_tab_ptr),link + fcmp,>,dbl fcycles,fcycles_stop ;C=1 if must stop + + addl scratch4,scratch2,scratch1 + comclr,>= scratch4,const_fd,0 ;stop for pieces if near end of page + + ldi -1,scratch2 + bb,<,n scratch2,BANK_IO_BIT,dispatch_instr_io + + ftest ;null next if can cont + + bv 0(link) + CYCLES_PLUS_2 + + b dispatch_instr_io + CYCLES_MINUS_2 + + + .align 32 + .export dispatch,code +dispatch + +#ifdef CHECK_SIZE_CONSISTENCY + nop + bl check_size_consist,link + nop +#endif + +#ifdef DEBUG_TOOLBOX + ldil l%g_rom_version,scratch1 + ldw r%g_rom_version(scratch1),scratch1 + ldi 0x00db,scratch1 ;ROM 01 + comiclr,> 3,scratch1,0 + ldi 0x00e5,scratch1 ;ROM 03 + depi -2,15,8,scratch1 ;set bank to 0xfe + comb,<>,n scratch1,kpc,no_debug_toolbox + copy xreg,arg0 + copy stack,arg1 + bl toolbox_debug_c,link + copy cycles,arg2 + + extru kpc,23,16,scratch2 +no_debug_toolbox +#endif + fldds 0(fcycles_stop_ptr),fcycles_stop + extru kpc,23,16,arg2 + + ldi 0xfd,scratch3 + ldwx,s arg2(page_info_ptr),scratch2 + + fcmp,<=,dbl fcycles,fcycles_stop ;C=1 if can cont + extru kpc,31,8,scratch4 + + ldbx scratch4(scratch2),instr + comclr,>= scratch4,scratch3,0 ;stop for pieces if near end of page + + ftest ;null next if can cont + + ldi -1,scratch2 + ldwx,s instr(inst_tab_ptr),link + + addl scratch4,scratch2,scratch1 + bb,<,n scratch2,BANK_IO_BIT,dispatch_instr_io + + ; depi 0,31,3,link + +#ifndef LOG_PC + bv 0(link) + CYCLES_PLUS_2 +#else + CYCLES_PLUS_2 + + .import log_pc_ptr,data + .import log_pc_start_ptr,data + .import log_pc_end_ptr,data + .export log_pc_asm +log_pc_asm +; save regs into log_pc_ptr, wrap around to log_pc_start_ptr if +; log_pc_ptr gets > log_pc_end_ptr + ldb 1(scratch1),scratch3 + dep neg,24,1,psr ;set neg + ldb 2(scratch1),scratch2 + ldil l%log_pc_ptr,scratch4 + ldb 3(scratch1),ret0 + fsub,dbl fcycles_last_dcycs,fr_plus_2,ftmp1 + dep scratch2,23,8,scratch3 + ldo r%log_pc_ptr(scratch4),scratch4 + dep instr,7,8,scratch3 + ldw 0(scratch4),scratch2 + dep ret0,15,8,scratch3 + copy kpc,ret1 + depi 0,30,1,psr ;zero + comiclr,<> 0,zero,0 + depi 1,30,1,psr ;set zero + stw scratch3,LOG_PC_INSTR(scratch2) + dep dbank,7,8,ret1 + copy acc,scratch3 + dep psr,15,16,scratch3 + fadd,dbl fcycles,ftmp1,ftmp1 + stw ret1,LOG_PC_DBANK_KPC(scratch2) + copy yreg,ret1 + stw scratch3,LOG_PC_PSR_ACC(scratch2) + dep xreg,15,16,ret1 + copy direct,scratch3 + fstds ftmp1,LOG_PC_DCYCS(scratch2) + ldw rs%log_pc_end_ptr-log_pc_ptr(scratch4),ret0 + dep stack,15,16,scratch3 + stw ret1,LOG_PC_XREG_YREG(scratch2) + addi LOG_PC_SIZE,scratch2,r31 + stw scratch3,LOG_PC_STACK_DIRECT(scratch2) + +; comb,>= r31,ret0,log_pc_oflow +; nop + + comclr,< r31,ret0,0 +; reload log_pc with log_pc_start_ptr + ldw rs%log_pc_start_ptr-log_pc_ptr(scratch4),r31 + + bv 0(link) + stw r31,0(scratch4) + +log_pc_oflow + ldil l%g_fcycles_stop,scratch3 + ldil l%halt_sim,ret0 + stw 0,r%g_fcycles_stop(scratch3) + ldi 2,arg0 + stw 0,r%g_fcycles_stop+4(scratch3) + stw arg0,r%halt_sim(ret0) + + ldw rs%log_pc_start_ptr-log_pc_ptr(scratch4),r31 + bv 0(link) + stw r31,0(scratch4) +#endif + + + .export dispatch_instr_io,code +dispatch_instr_io +; check if we're here because of timeout or halt required + fcmp,<=,dbl fcycles,fcycles_stop ;C=1 if we can cont + ldwx,s arg2(page_info_ptr),scratch2 + + ftest ;do next instr if must stop + b,n dispatch_done_clr_ret0 + + bb,>=,n scratch2,BANK_IO_BIT,dispatch_instr_pieces + + ldil l%0xc700,scratch1 + ldo r%0xc700(scratch1),scratch1 + addi 0x0a,scratch1,scratch2 + comb,= scratch1,kpc,dispatch_done + zdepi RET_C700,3,4,ret0 + + addi 0xd,scratch1,scratch3 + comb,= scratch2,kpc,dispatch_done + zdepi RET_C70A,3,4,ret0 + + comb,= scratch3,kpc,dispatch_done + zdepi RET_C70D,3,4,ret0 + + .export dispatch_instr_pieces,code +dispatch_instr_pieces +; fetch pc, get size from inst_info_ptr + bl get_mem_long_8,link + copy kpc,arg0 +; ret is instr + ldwx,s ret0(inst_tab_ptr),link + ldil l%sizes_tab,scratch4 + copy ret0,instr + ldo r%sizes_tab(scratch4),scratch4 + addi 1,kpc,arg0 + ldbx instr(scratch4),scratch2 +#ifdef LOG_PC +; save "real" link so call_log_pc can restore it + + stw link,STACK_SAVE_DISPATCH_LINK(sp) + LDC(call_log_pc,link) + stw instr,STACK_SAVE_INSTR(sp) +#endif + stw link,STACK_SAVE_DISP_PIECES_LINK(sp) + + ldi 0x1bea,ret0 + sh3add scratch2,0,scratch2 + ldo STACK_SAVE_TMP_INST(sp),scratch1 + blr scratch2,0 + addit,>= -48,scratch2,0 + +/* must correct cycle count so all instrs are called with cycls += 2 */ +/* since get_mem will auto-inc cycles by the number of bytes, we */ +/* need to "patch" things here, by adding 1 for 1byte, and subbing */ +/* from 3 and 4 byte instrs */ +; 0 + bv 0(link) + CYCLES_PLUS_1 + nop + nop + nop ! nop ! nop ! nop + nop ! nop ! nop ! nop + nop ! nop ! nop ! nop +; 1 + bl get_mem_long_8,link + nop + ldw STACK_SAVE_DISP_PIECES_LINK(sp),link + dep ret0,15,8,ret0 + ldo STACK_SAVE_TMP_INST(sp),scratch1 + bv 0(link) + stw ret0,0(scratch1) + nop ! nop + nop ! nop ! nop ! nop + nop ! nop ! nop ! nop +; 2 + bl get_mem_long_16,link + CYCLES_MINUS_1 + ldo STACK_SAVE_TMP_INST(sp),scratch1 + ldw STACK_SAVE_DISP_PIECES_LINK(sp),link + dep ret0,15,8,ret0 + bv 0(link) + stw ret0,0(scratch1) + nop + nop ! nop ! nop ! nop + nop ! nop ! nop ! nop +; 3 + bl get_mem_long_24,link + CYCLES_MINUS_2 + shd ret0,ret0,16,scratch2 + ldw STACK_SAVE_DISP_PIECES_LINK(sp),link + extru ret0,23,8,ret0 + ldo STACK_SAVE_TMP_INST(sp),scratch1 + dep ret0,23,8,scratch2 + bv 0(link) + stw scratch2,0(scratch1) + nop ! nop ! nop + nop ! nop ! nop ! nop +; 4 variable acc size + extru,<> psr,26,1,0 + bl,n get_mem_long_16,link + bl,n get_mem_long_8,link + CYCLES_MINUS_1 + ldw STACK_SAVE_DISP_PIECES_LINK(sp),link + ldo STACK_SAVE_TMP_INST(sp),scratch1 + dep ret0,15,8,ret0 + bv 0(link) + stw ret0,0(scratch1) + nop ! nop ! nop + nop ! nop ! nop ! nop +; 5 variable x size + extru,<> psr,27,1,0 + bl,n get_mem_long_16,link + bl,n get_mem_long_8,link + CYCLES_MINUS_1 + ldw STACK_SAVE_DISP_PIECES_LINK(sp),link + ldo STACK_SAVE_TMP_INST(sp),scratch1 + dep ret0,15,8,ret0 + bv 0(link) + stw ret0,0(scratch1) + nop ! nop ! nop + nop ! nop ! nop ! nop +; 6 = evil + break + + +#ifdef LOG_PC + .export call_log_pc,code +call_log_pc +; ret0 = operands +; must get instr = instruction +; and link = correct dispatch loc + ldw STACK_SAVE_INSTR(sp),instr + b log_pc_asm + ldw STACK_SAVE_DISPATCH_LINK(sp),link +#endif + +dispatch_done_clr_ret0 + nop ;just in case of bad nullification + b dispatch_done + ldi 0,ret0 + + +#ifdef CHECK_SIZE_CONSISTENCY + .import size_fail,code + + .export check_size_consist +check_size_consist + ldil l%table16,scratch1 + ldil l%table8,scratch2 + ldo r%table16(scratch1),scratch1 + bb,< psr,26,check_tab_8_bit + ldo r%table8(scratch2),scratch2 +; else 16 + comb,= scratch1,inst_tab_ptr,acc_size_ok + nop + + .export acc_tab_fail1 +acc_tab_fail1 + copy inst_tab_ptr,arg1 + copy scratch1,arg2 + bl size_fail,link + ldi 0x100,arg0 + b,n dispatch_done_clr_ret0 +; 8 + .export check_tab_8_bit +check_tab_8_bit + comb,= scratch2,inst_tab_ptr,acc_size_ok + nop + + .export acc_tab_fail0 +acc_tab_fail0 + copy inst_tab_ptr,arg1 + copy scratch2,arg2 + bl size_fail,link + ldi 0x101,arg0 + b dispatch_done + ldi 0,ret0 + + .export acc_size_ok +acc_size_ok + bv 0(link) + nop +#endif + + .align 8 +adc_binary_8_entry2 + extru psr,31,1,scratch3 + add ret0,scratch3,ret0 + + dep ret0,31,8,acc + extru ret0,31,8,zero + +/* and calc overflow */ + xor arg0,ret0,arg2 /* cmp binary add res w/ src1 */ + xor arg0,scratch2,scratch3 /* cmp signs of two inputs */ + extru ret0,24,1,neg + andcm arg2,scratch3,scratch3 /* and that with ~res. */ + extru ret0,23,1,scratch4 + extru scratch3,24,1,scratch3 + dep scratch4,31,1,psr /* set carry */ + b dispatch + dep scratch3,25,1,psr /* set overflow */ + + .align 8 + .export adc_binary_8 +adc_binary_8 + extru ret0,31,8,scratch2 + bb,>= psr,28,adc_binary_8_entry2 + add arg0,scratch2,ret0 + + + ldil l%dispatch,link + b adc_decimal_8 + ldo r%dispatch(link),link + + .export adc_decimal_8 +/* adds arg0 to scratch2 */ +/* acc8 (in arg0) and ret0 have already been added into ret0. Ignore that */ +adc_decimal_8 + ldi 0xf,scratch1 + extru psr,31,1,ret0 + + and arg0,scratch1,scratch3 + and scratch2,scratch1,scratch4 + + add scratch3,scratch4,ret1 + ldi 0xf0,arg3 + + add ret0,ret1,ret0 + + and arg0,arg3,scratch3 + addi -0xa,ret0,ret1 + + and scratch2,arg3,scratch4 + depi 1,27,4,ret1 + comiclr,> 0xa,ret0,0 + copy ret1,ret0 + + add scratch3,scratch4,ret1 + add ret0,ret1,ret0 + + extru ret0,24,1,ret1 + extru ret0,23,1,arg1 + xor ret1,arg1,ret1 + dep ret1,25,1,psr /* ov=((sum>>2) ^ (sum>>1) & 0x40 */ + + comiclr,> 0xa0,ret0,0 + addi 0x60,ret0,ret0 + + xor arg0,scratch2,scratch4 + extru ret0,31,8,zero + + extru,= scratch4,24,1,0 + depi 0,25,1,psr /* no overflow! */ + + + depi 0,31,1,psr + comiclr,> 0x100,ret0,0 + addi 1,psr,psr + + extru ret0,24,1,neg + bv 0(link) + dep zero,31,8,acc + + + + .align 8 + .export sbc_binary_8,code +sbc_binary_8 + extru ret0,31,8,scratch2 + bb,>= psr,28,adc_binary_8_entry2 + add arg0,scratch2,ret0 + + ldil l%dispatch,link + b sbc_decimal_8 + ldo r%dispatch(link),link + + +/* else decimal */ + .export sbc_decimal_8,code +sbc_decimal_8 +/* do arg0 - scratch2 = acc */ + ldi 0xf,scratch1 + extru psr,31,1,ret0 + + and scratch2,scratch1,scratch3 + and arg0,scratch1,scratch4 + + add scratch3,ret0,ret0 + + add ret0,scratch4,ret0 + ldi 0xf0,arg3 + + addi -0x6,ret0,ret1 + and scratch2,arg3,scratch3 + + and ret1,scratch1,ret1 /* sum2 = (sum - 0x6) & 0xf */ + and arg0,arg3,scratch4 + comiclr,<= 0x10,ret0,0 + copy ret1,ret0 /* sum = sum2 */ + + add scratch3,scratch4,ret1 + ldi 0xff,arg2 + add ret0,ret1,ret0 + + extru ret0,24,1,ret1 + addi 0xa0,ret0,scratch3 + extru ret0,23,1,arg3 + and scratch3,arg2,scratch3 /* (sum = sum + 0xa0) & 0xff */ + xor ret1,arg3,ret1 + + dep ret1,25,1,psr /* overflow = ((sum >> 2) ^ */ + /* (sum >> 1)) & 0x40 */ + + depi 0,31,1,psr + comiclr,<= 0x100,ret0,arg3 + or,TR scratch3,0,ret0 + addi 1,psr,psr + + and ret0,arg2,zero + extru ret0,24,1,neg + + xor arg0,scratch2,ret1 + + extru,= ret1,24,1,0 + depi 0,25,1,psr /* clear overflow */ + + bv 0(link) + dep ret0,31,8,acc + + + + .align 8 + .export adc_binary_16 +adc_binary_16 + extru ret0,31,16,scratch2 + bb,< psr,28,adc_decimal_16 + add arg0,scratch2,ret0 + +adc_binary_16_entry2 + extru psr,31,1,scratch1 + add ret0,scratch1,ret0 + + dep ret0,31,16,acc + extru ret0,31,16,zero + +/* and calc overflow */ + xor arg0,ret0,arg2 /* cmp binary add res w/ src1 */ + xor arg0,scratch2,scratch3 + extru ret0,16,1,neg + andcm arg2,scratch3,scratch3 /* and that with ~res. */ + extru ret0,15,1,scratch4 + extru scratch3,16,1,scratch3 + dep scratch4,31,1,psr /* set carry */ + b dispatch + dep scratch3,25,1,psr /* set overflow */ + + + .export adc_decimal_16 +adc_decimal_16 +/* must save arg0, scratch2 */ + stw arg0,STACK_SAVE_DECIMAL16_A(sp) + extru arg0,31,8,arg0 + stw scratch2,STACK_SAVE_DECIMAL16_B(sp) + bl adc_decimal_8,link + extru scratch2,31,8,scratch2 + + ldb STACK_SAVE_DECIMAL16_A+2(sp),arg0 + ldb STACK_SAVE_DECIMAL16_B+2(sp),scratch2 + bl adc_decimal_8,link + stw acc,STACK_SAVE_DECIMAL16_A(sp) + + ldw STACK_SAVE_DECIMAL16_A(sp),scratch1 + zdep acc,23,8,acc + dep scratch1,31,8,acc + b dispatch + copy acc,zero + + + .align 8 + .export sbc_binary_16,code +sbc_binary_16 + extru ret0,31,16,scratch2 + bb,>= psr,28,adc_binary_16_entry2 + add arg0,scratch2,ret0 + +/* else decimal */ + .export sbc_decimal_16,code +sbc_decimal_16 + stw arg0,STACK_SAVE_DECIMAL16_A(sp) + extru arg0,31,8,arg0 + stw scratch2,STACK_SAVE_DECIMAL16_B(sp) + bl sbc_decimal_8,link + extru scratch2,31,8,scratch2 + + ldb STACK_SAVE_DECIMAL16_A+2(sp),arg0 + ldb STACK_SAVE_DECIMAL16_B+2(sp),scratch2 + bl sbc_decimal_8,link + stw acc,STACK_SAVE_DECIMAL16_A(sp) + + ldw STACK_SAVE_DECIMAL16_A(sp),scratch1 + zdep acc,23,8,acc + dep scratch1,31,8,acc + b dispatch + copy acc,zero + + + + +#define ACC8 + .code +#define INCLUDE_RCSID_S +#include "defs_instr.h" +#include "8inst_s.h" +#undef INCLUDE_RCSID_S + .code +#undef SYM +#undef ACC8 + + .code +#include "defs_instr.h" +#include "16inst_s.h" + .code +#undef SYM + + .export inst00_8 + .export inst01_8 + .export inst02_8 + .export inst03_8 + .export inst04_8 + .export inst05_8 + .export inst06_8 + .export inst07_8 + .export inst08_8 + .export inst09_8 + .export inst0a_8 + .export inst0b_8 + .export inst0c_8 + .export inst0d_8 + .export inst0e_8 + .export inst0f_8 + + .export inst10_8 + .export inst11_8 + .export inst12_8 + .export inst13_8 + .export inst14_8 + .export inst15_8 + .export inst16_8 + .export inst17_8 + .export inst18_8 + .export inst19_8 + .export inst1a_8 + .export inst1b_8 + .export inst1c_8 + .export inst1d_8 + .export inst1e_8 + .export inst1f_8 + + .export inst20_8 + .export inst21_8 + .export inst22_8 + .export inst23_8 + .export inst24_8 + .export inst25_8 + .export inst26_8 + .export inst27_8 + .export inst28_8 + .export inst29_8 + .export inst2a_8 + .export inst2b_8 + .export inst2c_8 + .export inst2d_8 + .export inst2e_8 + .export inst2f_8 + + .export inst30_8 + .export inst31_8 + .export inst32_8 + .export inst33_8 + .export inst34_8 + .export inst35_8 + .export inst36_8 + .export inst37_8 + .export inst38_8 + .export inst39_8 + .export inst3a_8 + .export inst3b_8 + .export inst3c_8 + .export inst3d_8 + .export inst3e_8 + .export inst3f_8 + + .export inst40_8 + .export inst41_8 + .export inst42_8 + .export inst43_8 + .export inst44_8 + .export inst45_8 + .export inst46_8 + .export inst47_8 + .export inst48_8 + .export inst49_8 + .export inst4a_8 + .export inst4b_8 + .export inst4c_8 + .export inst4d_8 + .export inst4e_8 + .export inst4f_8 + + .export inst50_8 + .export inst51_8 + .export inst52_8 + .export inst53_8 + .export inst54_8 + .export inst55_8 + .export inst56_8 + .export inst57_8 + .export inst58_8 + .export inst59_8 + .export inst5a_8 + .export inst5b_8 + .export inst5c_8 + .export inst5d_8 + .export inst5e_8 + .export inst5f_8 + + .export inst60_8 + .export inst61_8 + .export inst62_8 + .export inst63_8 + .export inst64_8 + .export inst65_8 + .export inst66_8 + .export inst67_8 + .export inst68_8 + .export inst69_8 + .export inst6a_8 + .export inst6b_8 + .export inst6c_8 + .export inst6d_8 + .export inst6e_8 + .export inst6f_8 + + .export inst70_8 + .export inst71_8 + .export inst72_8 + .export inst73_8 + .export inst74_8 + .export inst75_8 + .export inst76_8 + .export inst77_8 + .export inst78_8 + .export inst79_8 + .export inst7a_8 + .export inst7b_8 + .export inst7c_8 + .export inst7d_8 + .export inst7e_8 + .export inst7f_8 + + .export inst80_8 + .export inst81_8 + .export inst82_8 + .export inst83_8 + .export inst84_8 + .export inst85_8 + .export inst86_8 + .export inst87_8 + .export inst88_8 + .export inst89_8 + .export inst8a_8 + .export inst8b_8 + .export inst8c_8 + .export inst8d_8 + .export inst8e_8 + .export inst8f_8 + .export inst90_8 + .export inst91_8 + .export inst92_8 + .export inst93_8 + .export inst94_8 + .export inst95_8 + .export inst96_8 + .export inst97_8 + .export inst98_8 + .export inst99_8 + .export inst9a_8 + .export inst9b_8 + .export inst9c_8 + .export inst9d_8 + .export inst9e_8 + .export inst9f_8 + .export insta0_8 + .export insta1_8 + .export insta2_8 + .export insta3_8 + .export insta4_8 + .export insta5_8 + .export insta6_8 + .export insta7_8 + .export insta8_8 + .export insta9_8 + .export instaa_8 + .export instab_8 + .export instac_8 + .export instad_8 + .export instae_8 + .export instaf_8 + .export instb0_8 + .export instb1_8 + .export instb2_8 + .export instb3_8 + .export instb4_8 + .export instb5_8 + .export instb6_8 + .export instb7_8 + .export instb8_8 + .export instb9_8 + .export instba_8 + .export instbb_8 + .export instbc_8 + .export instbd_8 + .export instbe_8 + .export instbf_8 + .export instc0_8 + .export instc1_8 + .export instc2_8 + .export instc3_8 + .export instc4_8 + .export instc5_8 + .export instc6_8 + .export instc7_8 + .export instc8_8 + .export instc9_8 + .export instca_8 + .export instcb_8 + .export instcc_8 + .export instcd_8 + .export instce_8 + .export instcf_8 + .export instd0_8 + .export instd1_8 + .export instd2_8 + .export instd3_8 + .export instd4_8 + .export instd5_8 + .export instd6_8 + .export instd7_8 + .export instd8_8 + .export instd9_8 + .export instda_8 + .export instdb_8 + .export instdc_8 + .export instdd_8 + .export instde_8 + .export instdf_8 + .export inste0_8 + .export inste1_8 + .export inste2_8 + .export inste3_8 + .export inste4_8 + .export inste5_8 + .export inste6_8 + .export inste7_8 + .export inste8_8 + .export inste9_8 + .export instea_8 + .export insteb_8 + .export instec_8 + .export insted_8 + .export instee_8 + .export instef_8 + .export instf0_8 + .export instf1_8 + .export instf2_8 + .export instf3_8 + .export instf4_8 + .export instf5_8 + .export instf6_8 + .export instf7_8 + .export instf8_8 + .export instf9_8 + .export instfa_8 + .export instfb_8 + .export instfc_8 + .export instfd_8 + .export instfe_8 + .export instff_8 + + + .export inst00_16 + .export inst01_16 + .export inst02_16 + .export inst03_16 + .export inst04_16 + .export inst05_16 + .export inst06_16 + .export inst07_16 + .export inst08_16 + .export inst09_16 + .export inst0a_16 + .export inst0b_16 + .export inst0c_16 + .export inst0d_16 + .export inst0e_16 + .export inst0f_16 + + .export inst10_16 + .export inst11_16 + .export inst12_16 + .export inst13_16 + .export inst14_16 + .export inst15_16 + .export inst16_16 + .export inst17_16 + .export inst18_16 + .export inst19_16 + .export inst1a_16 + .export inst1b_16 + .export inst1c_16 + .export inst1d_16 + .export inst1e_16 + .export inst1f_16 + + .export inst20_16 + .export inst21_16 + .export inst22_16 + .export inst23_16 + .export inst24_16 + .export inst25_16 + .export inst26_16 + .export inst27_16 + .export inst28_16 + .export inst29_16 + .export inst2a_16 + .export inst2b_16 + .export inst2c_16 + .export inst2d_16 + .export inst2e_16 + .export inst2f_16 + + .export inst30_16 + .export inst31_16 + .export inst32_16 + .export inst33_16 + .export inst34_16 + .export inst35_16 + .export inst36_16 + .export inst37_16 + .export inst38_16 + .export inst39_16 + .export inst3a_16 + .export inst3b_16 + .export inst3c_16 + .export inst3d_16 + .export inst3e_16 + .export inst3f_16 + + .export inst40_16 + .export inst41_16 + .export inst42_16 + .export inst43_16 + .export inst44_16 + .export inst45_16 + .export inst46_16 + .export inst47_16 + .export inst48_16 + .export inst49_16 + .export inst4a_16 + .export inst4b_16 + .export inst4c_16 + .export inst4d_16 + .export inst4e_16 + .export inst4f_16 + + .export inst50_16 + .export inst51_16 + .export inst52_16 + .export inst53_16 + .export inst54_16 + .export inst55_16 + .export inst56_16 + .export inst57_16 + .export inst58_16 + .export inst59_16 + .export inst5a_16 + .export inst5b_16 + .export inst5c_16 + .export inst5d_16 + .export inst5e_16 + .export inst5f_16 + + .export inst60_16 + .export inst61_16 + .export inst62_16 + .export inst63_16 + .export inst64_16 + .export inst65_16 + .export inst66_16 + .export inst67_16 + .export inst68_16 + .export inst69_16 + .export inst6a_16 + .export inst6b_16 + .export inst6c_16 + .export inst6d_16 + .export inst6e_16 + .export inst6f_16 + + .export inst70_16 + .export inst71_16 + .export inst72_16 + .export inst73_16 + .export inst74_16 + .export inst75_16 + .export inst76_16 + .export inst77_16 + .export inst78_16 + .export inst79_16 + .export inst7a_16 + .export inst7b_16 + .export inst7c_16 + .export inst7d_16 + .export inst7e_16 + .export inst7f_16 + + .export inst80_16 + .export inst81_16 + .export inst82_16 + .export inst83_16 + .export inst84_16 + .export inst85_16 + .export inst86_16 + .export inst87_16 + .export inst88_16 + .export inst89_16 + .export inst8a_16 + .export inst8b_16 + .export inst8c_16 + .export inst8d_16 + .export inst8e_16 + .export inst8f_16 + .export inst90_16 + .export inst91_16 + .export inst92_16 + .export inst93_16 + .export inst94_16 + .export inst95_16 + .export inst96_16 + .export inst97_16 + .export inst98_16 + .export inst99_16 + .export inst9a_16 + .export inst9b_16 + .export inst9c_16 + .export inst9d_16 + .export inst9e_16 + .export inst9f_16 + .export insta0_16 + .export insta1_16 + .export insta2_16 + .export insta3_16 + .export insta4_16 + .export insta5_16 + .export insta6_16 + .export insta7_16 + .export insta8_16 + .export insta9_16 + .export instaa_16 + .export instab_16 + .export instac_16 + .export instad_16 + .export instae_16 + .export instaf_16 + .export instb0_16 + .export instb1_16 + .export instb2_16 + .export instb3_16 + .export instb4_16 + .export instb5_16 + .export instb6_16 + .export instb7_16 + .export instb8_16 + .export instb9_16 + .export instba_16 + .export instbb_16 + .export instbc_16 + .export instbd_16 + .export instbe_16 + .export instbf_16 + .export instc0_16 + .export instc1_16 + .export instc2_16 + .export instc3_16 + .export instc4_16 + .export instc5_16 + .export instc6_16 + .export instc7_16 + .export instc8_16 + .export instc9_16 + .export instca_16 + .export instcb_16 + .export instcc_16 + .export instcd_16 + .export instce_16 + .export instcf_16 + .export instd0_16 + .export instd1_16 + .export instd2_16 + .export instd3_16 + .export instd4_16 + .export instd5_16 + .export instd6_16 + .export instd7_16 + .export instd8_16 + .export instd9_16 + .export instda_16 + .export instdb_16 + .export instdc_16 + .export instdd_16 + .export instde_16 + .export instdf_16 + .export inste0_16 + .export inste1_16 + .export inste2_16 + .export inste3_16 + .export inste4_16 + .export inste5_16 + .export inste6_16 + .export inste7_16 + .export inste8_16 + .export inste9_16 + .export instea_16 + .export insteb_16 + .export instec_16 + .export insted_16 + .export instee_16 + .export instef_16 + .export instf0_16 + .export instf1_16 + .export instf2_16 + .export instf3_16 + .export instf4_16 + .export instf5_16 + .export instf6_16 + .export instf7_16 + .export instf8_16 + .export instf9_16 + .export instfa_16 + .export instfb_16 + .export instfc_16 + .export instfd_16 + .export instfe_16 + .export instff_16 + + + .data +#define INCLUDE_RCSID_S +#include "8size_s.h" +#undef INCLUDE_RCSID_S + + .export table8,data +table8 +#include "8size_s.h" + + .export table16,data +table16 +#include "16size_s.h" + + .export sizes_tab,data +sizes_tab +#include "size_s.h" + + + .export g_engine_c_mode,data +g_engine_c_mode + .word 0 + + .bss + + .export slow_memory,data + .export rom_fc_ff,data + .export rom_cards,data + .export dummy_memory1,data + .align 0x100 +slow_memory .block 128*1024 +dummy_memory1 .block 3*1024 +rom_fc_ff .block 256*1024 +rom_cards .block 256*16 + diff --git a/src/info.nib b/src/info.nib new file mode 100644 index 0000000..4fcb7b8 --- /dev/null +++ b/src/info.nib @@ -0,0 +1,19 @@ + + + + + IBDocumentLocation + 152 85 356 240 0 0 1280 832 + IBEditorPositions + + 29 + 69 252 182 44 0 0 1280 832 + + IBFramework Version + 291.0 + IBSystem Version + 6R73 + targetFramework + IBCarbonFramework + + diff --git a/src/instable.h b/src/instable.h new file mode 100644 index 0000000..d350611 --- /dev/null +++ b/src/instable.h @@ -0,0 +1,2703 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef ASM +# ifdef INCLUDE_RCSID_S + .stringz "@(#)$KmKId: instable.h,v 1.103 2004-01-10 15:50:50-05 kentd Exp $" +# endif +#endif + +inst00_SYM /* brk */ +#ifdef ASM + ldb 1(scratch1),ret0 + ldil l%g_testing,arg3 + ldil l%g_num_brk,arg1 + ldw r%g_testing(arg3),arg3 + INC_KPC_2; + ldw r%g_num_brk(arg1),arg2 + comib,<> 0,arg3,brk_testing_SYM + extru kpc,31,16,arg0 + addi 1,arg2,arg2 + bb,>= psr,23,brk_native_SYM + stw arg2,r%g_num_brk(arg1) + + bl push_16,link + nop + + bl push_8,link + extru psr,31,8,arg0 ;B bit already on in PSR + + ldil l%0xfffe,arg0 + bl get_mem_long_16,link + ldo r%0xfffe(arg0),arg0 + + zdep ret0,31,16,kpc ;set kbank to 0 + +#if 0 + bl set_halt_act,link + ldi 3,arg0 +#endif + + + ldi 0,dbank ;clear dbank in emul mode + b dispatch + depi 1,29,2,psr ;ints masked, decimal off + + +brk_native_SYM + stw arg0,STACK_SAVE_COP_ARG0(sp) + bl push_8,link + extru kpc,15,8,arg0 + + bl push_16,link + ldw STACK_SAVE_COP_ARG0(sp),arg0 + + bl push_8,link + extru psr,31,8,arg0 + + ldil l%0xffe6,arg0 + bl get_mem_long_16,link + ldo r%0xffe6(arg0),arg0 + + zdep ret0,31,16,kpc ;zero kbank in kpc + +#if 0 +#endif + bl set_halt_act,link + ldi 3,arg0 + + b dispatch + depi 1,29,2,psr ;ints masked, decimal off + +brk_testing_SYM + DEC_KPC2; + CYCLES_PLUS_2 + b dispatch_done + depi RET_BREAK,3,4,ret0 + +#else + GET_1BYTE_ARG; + if(g_testing) { + CYCLES_PLUS_2; + FINISH(RET_BREAK, arg); + } + g_num_brk++; + INC_KPC_2; + if(psr & 0x100) { + PUSH16(kpc & 0xffff); + PUSH8(psr & 0xff); + GET_MEMORY16(0xfffe, kpc, 0); + dbank = 0; + } else { + PUSH8(kpc >> 16); + PUSH16(kpc); + PUSH8(psr & 0xff); + GET_MEMORY16(0xffe6, kpc, 0); + halt_printf("Halting for native break!\n"); + } + kpc = kpc & 0xffff; + psr |= 0x4; + psr &= ~(0x8); +#endif + +inst01_SYM /* ORA (Dloc,X) */ +/* called with arg = val to ORA in */ + GET_DLOC_X_IND_RD(); + ORA_INST(); + +inst02_SYM /* COP */ +#ifdef ASM + ldil l%g_num_cop,arg1 + INC_KPC_2; + ldw r%g_num_cop(arg1),arg2 + extru kpc,31,16,arg0 + addi 1,arg2,arg2 + bb,>= psr,23,cop_native_SYM + stw arg2,r%g_num_cop(arg1) + + bl push_16,link + nop + + bl push_8,link + extru psr,31,8,arg0 + + ldil l%0xfff4,arg0 + bl get_mem_long_16,link + ldo r%0xfff4(arg0),arg0 + + ldi 0,dbank ;clear dbank in emul mode + zdep ret0,31,16,kpc ;clear kbank + + bl set_halt_act,link + ldi 3,arg0 + + b dispatch + depi 1,29,2,psr ;ints masked, decimal off + +cop_native_SYM + stw arg0,STACK_SAVE_COP_ARG0(sp) + bl push_8,link + extru kpc,15,8,arg0 + + bl push_16,link + ldw STACK_SAVE_COP_ARG0(sp),arg0 + + bl push_8,link + extru psr,31,8,arg0 + + ldil l%0xffe4,arg0 + bl get_mem_long_16,link + ldo r%0xffe4(arg0),arg0 + + zdep ret0,31,16,kpc ;clear kbank + b dispatch + depi 1,29,2,psr ;ints masked, decimal off + + +#else + g_num_cop++; + INC_KPC_2; + if(psr & 0x100) { + halt_printf("Halting for emul COP at %04x\n", kpc); + PUSH16(kpc & 0xffff); + PUSH8(psr & 0xff); + GET_MEMORY16(0xfff4, kpc, 0); + dbank = 0; + } else { + PUSH8(kpc >> 16); + PUSH16(kpc & 0xffff); + PUSH8(psr & 0xff); + GET_MEMORY16(0xffe4, kpc, 0); + } + kpc = kpc & 0xffff; + psr |= 4; + psr &= ~(0x8); +#endif + +inst03_SYM /* ORA Disp8,S */ + GET_DISP8_S_RD(); + ORA_INST(); + +inst04_SYM /* TSB Dloc */ + GET_DLOC_RD(); + TSB_INST(1); + +inst05_SYM /* ORA Dloc */ + GET_DLOC_RD(); + ORA_INST(); + +inst06_SYM /* ASL Dloc */ + GET_DLOC_RD(); + ASL_INST(1); + +inst07_SYM /* ORA [Dloc] */ + GET_DLOC_L_IND_RD(); + ORA_INST(); + +inst08_SYM /* PHP */ +#ifdef ASM + dep neg,24,1,psr + ldil l%dispatch,link + INC_KPC_1 + depi 0,30,1,psr + comiclr,<> 0,zero,0 + depi 1,30,1,psr + ldo r%dispatch(link),link + b push_8 + extru psr,31,8,arg0 +#else + INC_KPC_1; + psr = (psr & ~0x82) | ((neg & 1) << 7) | ((!zero) << 1); + PUSH8(psr); +#endif + +inst09_SYM /* ORA #imm */ + GET_IMM_MEM(); + ORA_INST(); + +inst0a_SYM /* ASL a */ +#ifdef ASM +# ifdef ACC8 + ldi 0xff,scratch1 + sh1add acc,0,scratch3 + INC_KPC_1 + extru scratch3,24,1,neg + and scratch3,scratch1,zero + extru scratch3,23,1,scratch2 + dep zero,31,8,acc + b dispatch + dep scratch2,31,1,psr /* set carry */ +# else + zdepi -1,31,16,scratch1 + sh1add acc,0,scratch3 + INC_KPC_1 + extru scratch3,16,1,neg + and scratch3,scratch1,zero + extru scratch3,15,1,scratch2 + dep scratch2,31,1,psr /* set carry */ + b dispatch + dep zero,31,16,acc +# endif +#else + INC_KPC_1; + tmp1 = acc + acc; +# ifdef ACC8 + SET_CARRY8(tmp1); + acc = (acc & 0xff00) + (tmp1 & 0xff); + SET_NEG_ZERO8(acc & 0xff); +# else + SET_CARRY16(tmp1); + acc = tmp1 & 0xffff; + SET_NEG_ZERO16(acc); +# endif +#endif + +inst0b_SYM /* PHD */ +#ifdef ASM + ldil l%dispatch,link + extru direct,31,16,arg0 + INC_KPC_1 + b push_16_unsafe + ldo r%dispatch(link),link +#else + INC_KPC_1; + PUSH16_UNSAFE(direct); +#endif + +inst0c_SYM /* TSB abs */ + GET_ABS_RD(); + TSB_INST(0); + +inst0d_SYM /* ORA abs */ + GET_ABS_RD(); + ORA_INST(); + +inst0e_SYM /* ASL abs */ + GET_ABS_RD(); + ASL_INST(0); + +inst0f_SYM /* ORA long */ + GET_LONG_RD(); + ORA_INST(); + + +inst10_SYM /* BPL disp8 */ +#ifdef ASM + COND_BR1 + comib,<> 0,neg,inst10_2_SYM + COND_BR2 + +inst10_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8(neg == 0); +#endif + +inst11_SYM /* ORA (Dloc),y */ + GET_DLOC_IND_Y_RD(); + ORA_INST(); + +inst12_SYM /* ORA (Dloc) */ + GET_DLOC_IND_RD(); + ORA_INST(); + +inst13_SYM /* ORA (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + ORA_INST(); + +inst14_SYM /* TRB Dloc */ + GET_DLOC_RD(); + TRB_INST(1); + +inst15_SYM /* ORA Dloc,x */ + GET_DLOC_X_RD(); + ORA_INST(); + +inst16_SYM /* ASL Dloc,X */ + GET_DLOC_X_RD(); + ASL_INST(1); + +inst17_SYM /* ORA [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + ORA_INST(); + +inst18_SYM /* CLC */ +#ifdef ASM + INC_KPC_1 + b dispatch + depi 0,31,1,psr /* clear carry */ +#else + psr = psr & (~1); + INC_KPC_1; +#endif + +inst19_SYM /* ORA abs,y */ + GET_ABS_Y_RD(); + ORA_INST(); + + +inst1a_SYM /* INC a */ +#ifdef ASM +# ifdef ACC8 + ldi 0xff,scratch2 + addi 1,acc,scratch1 + extru scratch1,24,1,neg + INC_KPC_1 + extru scratch1,31,8,zero + b dispatch + dep zero,31,8,acc +# else + zdepi -1,31,16,scratch2 + addi 1,acc,scratch1 + extru scratch1,16,1,neg + INC_KPC_1 + extru scratch1,31,16,zero + b dispatch + dep zero,31,16,acc +# endif +#else + INC_KPC_1; +# ifdef ACC8 + acc = (acc & 0xff00) | ((acc + 1) & 0xff); + SET_NEG_ZERO8(acc & 0xff); +# else + acc = (acc + 1) & 0xffff; + SET_NEG_ZERO16(acc); +# endif +#endif + +inst1b_SYM /* TCS */ +#ifdef ASM + copy acc,stack + extru,= psr,23,1,0 /* in emulation mode, stack page 1 */ + depi 1,23,24,stack + INC_KPC_1 + b dispatch + nop +#else + stack = acc; + INC_KPC_1; + if(psr & 0x100) { + stack = (stack & 0xff) + 0x100; + } +#endif + +inst1c_SYM /* TRB Abs */ + GET_ABS_RD(); + TRB_INST(0); + +inst1d_SYM /* ORA Abs,X */ + GET_ABS_X_RD(); + ORA_INST(); + +inst1e_SYM /* ASL Abs,X */ + GET_ABS_X_RD_WR(); + ASL_INST(0); + +inst1f_SYM /* ORA Long,X */ + GET_LONG_X_RD(); + ORA_INST(); + + +inst20_SYM /* JSR abs */ +#ifdef ASM + addi 2,kpc,arg0 + ldb 1(scratch1),scratch2 + CYCLES_PLUS_2 + ldb 2(scratch1),scratch1 + ldil l%dispatch,link + extru arg0,31,16,arg0 + ldo r%dispatch(link),link + dep scratch2,31,8,kpc + b push_16 + dep scratch1,23,8,kpc +#else + GET_2BYTE_ARG; + INC_KPC_2; + PUSH16(kpc); + kpc = (kpc & 0xff0000) + arg; + CYCLES_PLUS_2; +#endif + +inst21_SYM /* AND (Dloc,X) */ +/* called with arg = val to AND in */ + GET_DLOC_X_IND_RD(); + AND_INST(); + +inst22_SYM /* JSL Long */ +#ifdef ASM + INC_KPC_3 + ldb 3(scratch1),scratch2 + copy kpc,arg0 + ldb 1(scratch1),kpc + ldb 2(scratch1),scratch1 + CYCLES_PLUS_3 + dep scratch2,15,8,kpc + stw scratch2,STACK_SAVE_INSTR_TMP1(sp) + bl push_24_unsafe,link + dep scratch1,23,8,kpc + + b dispatch + nop +#else + GET_3BYTE_ARG; + tmp1 = arg; + CYCLES_PLUS_3; + INC_KPC_3; + PUSH24_UNSAFE(kpc); + kpc = tmp1 & 0xffffff; +#endif + +inst23_SYM /* AND Disp8,S */ +/* called with arg = val to AND in */ + GET_DISP8_S_RD(); + AND_INST(); + +inst24_SYM /* BIT Dloc */ + GET_DLOC_RD(); + BIT_INST(); + +inst25_SYM /* AND Dloc */ +/* called with arg = val to AND in */ + GET_DLOC_RD(); + AND_INST(); + +inst26_SYM /* ROL Dloc */ + GET_DLOC_RD(); +/* save1 is now apple addr */ +/* ret0 is data */ + ROL_INST(1); + +inst27_SYM /* AND [Dloc] */ + GET_DLOC_L_IND_RD(); + AND_INST(); + +inst28_SYM /* PLP */ +#ifdef ASM + bl pull_8,link + ldi 0,zero + + extru psr,27,2,scratch2 /* save old x & m */ + dep ret0,31,8,psr + CYCLES_PLUS_1 + INC_KPC_1 + extru,<> ret0,30,1,0 + ldi 1,zero + copy scratch2,arg0 + b update_system_state + extru ret0,24,1,neg +#else + PULL8(tmp1); + tmp2 = psr; + CYCLES_PLUS_1; + INC_KPC_1; + psr = (psr & ~0xff) | (tmp1 & 0xff); + zero = !(psr & 2); + neg = (psr >> 7) & 1; + UPDATE_PSR(psr, tmp2); +#endif + + +inst29_SYM /* AND #imm */ + GET_IMM_MEM(); + AND_INST(); + +inst2a_SYM /* ROL a */ +#ifdef ASM +# ifdef ACC8 + extru psr,31,1,scratch2 + ldi 0xff,scratch1 + sh1add acc,scratch2,scratch3 + INC_KPC_1 + extru scratch3,24,1,neg + and scratch3,scratch1,zero + extru scratch3,23,1,scratch2 + dep zero,31,8,acc + b dispatch + dep scratch2,31,1,psr /* set carry */ +# else + extru psr,31,1,scratch2 + INC_KPC_1 + sh1add acc,scratch2,scratch3 + zdepi -1,31,16,scratch1 + extru scratch3,16,1,neg + and scratch3,scratch1,zero + extru scratch3,15,1,scratch2 + dep scratch2,31,1,psr /* set carry */ + b dispatch + dep zero,31,16,acc +# endif +#else + INC_KPC_1; +# ifdef ACC8 + tmp1 = ((acc & 0xff) << 1) + (psr & 1); + SET_CARRY8(tmp1); + acc = (acc & 0xff00) + (tmp1 & 0xff); + SET_NEG_ZERO8(tmp1 & 0xff); +# else + tmp1 = (acc << 1) + (psr & 1); + SET_CARRY16(tmp1); + acc = (tmp1 & 0xffff); + SET_NEG_ZERO16(acc); +# endif +#endif + +inst2b_SYM /* PLD */ +#ifdef ASM + INC_KPC_1 + bl pull_16_unsafe,link + CYCLES_PLUS_1 + extru ret0,31,16,direct + extru ret0,16,1,neg + b dispatch + copy direct,zero +#else + INC_KPC_1; + PULL16_UNSAFE(direct); + CYCLES_PLUS_1; + SET_NEG_ZERO16(direct); +#endif + +inst2c_SYM /* BIT abs */ + GET_ABS_RD(); + BIT_INST(); + +inst2d_SYM /* AND abs */ + GET_ABS_RD(); + AND_INST(); + +inst2e_SYM /* ROL abs */ + GET_ABS_RD(); + ROL_INST(0); + +inst2f_SYM /* AND long */ + GET_LONG_RD(); + AND_INST(); + + +inst30_SYM /* BMI disp8 */ +#ifdef ASM + COND_BR1 + comib,= 0,neg,inst30_2_SYM + COND_BR2 + +inst30_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8(neg); +#endif + +inst31_SYM /* AND (Dloc),y */ + GET_DLOC_IND_Y_RD(); + AND_INST(); + +inst32_SYM /* AND (Dloc) */ + GET_DLOC_IND_RD(); + AND_INST(); + +inst33_SYM /* AND (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + AND_INST(); + +inst34_SYM /* BIT Dloc,x */ + GET_DLOC_X_RD(); + BIT_INST(); + +inst35_SYM /* AND Dloc,x */ + GET_DLOC_X_RD(); + AND_INST(); + +inst36_SYM /* ROL Dloc,X */ + GET_DLOC_X_RD(); + ROL_INST(1); + +inst37_SYM /* AND [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + AND_INST(); + +inst38_SYM /* SEC */ +#ifdef ASM + INC_KPC_1 + b dispatch + depi 1,31,1,psr /* set carry */ +#else + psr = psr | 1; + INC_KPC_1; +#endif + +inst39_SYM /* AND abs,y */ + GET_ABS_Y_RD(); + AND_INST(); + +inst3a_SYM /* DEC a */ +#ifdef ASM +# ifdef ACC8 + addi -1,acc,scratch1 + extru scratch1,24,1,neg + INC_KPC_1 + extru scratch1,31,8,zero + b dispatch + dep zero,31,8,acc +# else + addi -1,acc,scratch1 + extru scratch1,16,1,neg + INC_KPC_1 + extru scratch1,31,16,zero + b dispatch + dep zero,31,16,acc +# endif +#else + INC_KPC_1; +# ifdef ACC8 + acc = (acc & 0xff00) | ((acc - 1) & 0xff); + SET_NEG_ZERO8(acc & 0xff); +# else + acc = (acc - 1) & 0xffff; + SET_NEG_ZERO16(acc); +# endif +#endif + +inst3b_SYM /* TSC */ +/* set N,Z according to 16 bit acc */ +#ifdef ASM + copy stack,acc + extru stack,16,1,neg + INC_KPC_1 + b dispatch + extru acc,31,16,zero +#else + INC_KPC_1; + acc = stack; + SET_NEG_ZERO16(acc); +#endif + +inst3c_SYM /* BIT Abs,x */ + GET_ABS_X_RD(); + BIT_INST(); + +inst3d_SYM /* AND Abs,X */ + GET_ABS_X_RD(); + AND_INST(); + +inst3e_SYM /* ROL Abs,X */ + GET_ABS_X_RD_WR(); + ROL_INST(0); + +inst3f_SYM /* AND Long,X */ + GET_LONG_X_RD(); + AND_INST(); + + +inst40_SYM /* RTI */ +#ifdef ASM + bb,>= psr,23,rti_native_SYM + CYCLES_PLUS_1 +/* emulation */ + bl pull_24,link + ldi 0,zero + + extru psr,27,2,scratch2 + extru ret0,23,16,scratch3 + copy scratch2,arg0 + extru,<> ret0,30,1,0 + ldi 1,zero + dep ret0,31,8,psr + + extru ret0,24,1,neg + b update_system_state + dep scratch3,31,16,kpc + +rti_native_SYM + bl pull_8,link + ldi 0,zero + + copy ret0,scratch1 + extru ret0,24,1,neg + dep ret0,31,8,scratch1 + bl pull_24,link + stw scratch1,STACK_SAVE_INSTR_TMP1(sp) + + extru psr,27,2,scratch2 + ldw STACK_SAVE_INSTR_TMP1(sp),psr + extru ret0,31,24,kpc + extru,<> psr,30,1,0 + ldi 1,zero + + b update_system_state_and_change_kbank + copy scratch2,arg0 +#else + CYCLES_PLUS_1 + if(psr & 0x100) { + PULL24(tmp1); + kpc = (kpc & 0xff0000) + ((tmp1 >> 8) & 0xffff); + tmp2 = psr; + psr = (psr & ~0xff) + (tmp1 & 0xff); + neg = (psr >> 7) & 1; + zero = !(psr & 2); + UPDATE_PSR(psr, tmp2); + } else { + PULL8(tmp1); + tmp2 = psr; + psr = (tmp1 & 0xff); + neg = (psr >> 7) & 1; + zero = !(psr & 2); + PULL24(kpc); + UPDATE_PSR(psr, tmp2); + } +#endif + + +inst41_SYM /* EOR (Dloc,X) */ +/* called with arg = val to EOR in */ + GET_DLOC_X_IND_RD(); + EOR_INST(); + +inst42_SYM /* WDM */ +#ifdef ASM + ldb 1(scratch1),ret0 + CYCLES_PLUS_5 + CYCLES_PLUS_2 + INC_KPC_2 + b dispatch_done + depi RET_WDM,3,4,ret0 +#else + GET_1BYTE_ARG; + INC_KPC_2; + CYCLES_PLUS_5; + CYCLES_PLUS_2; + FINISH(RET_WDM, arg & 0xff); +#endif + +inst43_SYM /* EOR Disp8,S */ +/* called with arg = val to EOR in */ + GET_DISP8_S_RD(); + EOR_INST(); + +inst44_SYM /* MVP */ +#ifdef ASM + ldb 2(scratch1),scratch2 /* src bank */ + bb,< psr,23,inst44_notnat_SYM + ldb 1(scratch1),dbank /* dest bank */ + bb,< psr,27,inst44_notnat_SYM + stw scratch2,STACK_SRC_BANK(sp) + +inst44_loop_SYM + CYCLES_PLUS_1 + ldw STACK_SRC_BANK(sp),scratch2 + copy xreg,arg0 + + bl get_mem_long_8,link + dep scratch2,15,8,arg0 +/* got byte */ + copy ret0,arg1 + copy yreg,arg0 + bl set_mem_long_8,link + dep dbank,15,8,arg0 +/* wrote byte, dec acc */ + CYCLES_PLUS_2 + fldds 0(fcycles_stop_ptr),fcycles_stop + addi -1,xreg,xreg + zdepi -1,31,16,scratch2 + addi -1,yreg,yreg + addi -1,acc,acc + fcmp,<,dbl fcycles,fcycles_stop + and xreg,scratch2,xreg + extrs acc,31,16,scratch1 + and yreg,scratch2,yreg + + comib,= -1,scratch1,inst44_done_SYM + and acc,scratch2,acc + + ftest + b inst44_out_of_time_SYM + + CYCLES_PLUS_2 + b inst44_loop_SYM + nop + +/* get here if done */ +inst44_done_SYM + INC_KPC_3 + b dispatch + nop + +inst44_notnat_SYM + copy dbank,ret0 + dep scratch2,23,8,ret0 + CYCLES_PLUS_3 + depi RET_MVP,3,4,ret0 + b dispatch_done + CYCLES_PLUS_2 + +inst44_out_of_time_SYM +/* cycle have gone positive, just get out, do not update kpc */ + b,n dispatch +#else + GET_2BYTE_ARG; + /* arg & 0xff = dest bank, arg & 0xff00 = src bank */ + if(psr & 0x110) { + halt_printf("MVP but not native m or x!\n"); + break; + } + CYCLES_MINUS_2 + dbank = arg & 0xff; + tmp1 = (arg >> 8) & 0xff; + while(1) { + CYCLES_PLUS_3; + GET_MEMORY8((tmp1 << 16) + xreg, arg); + SET_MEMORY8((dbank << 16) + yreg, arg); + CYCLES_PLUS_2; + xreg = (xreg - 1) & 0xffff; + yreg = (yreg - 1) & 0xffff; + acc = (acc - 1) & 0xffff; + if(acc == 0xffff) { + INC_KPC_3; + break; + } + if(fcycles >= g_fcycles_stop) { + break; + } + } +#endif + + +inst45_SYM /* EOR Dloc */ +/* called with arg = val to EOR in */ + GET_DLOC_RD(); + EOR_INST(); + +inst46_SYM /* LSR Dloc */ + GET_DLOC_RD(); +/* save1 is now apple addr */ +/* ret0 is data */ + LSR_INST(1); + +inst47_SYM /* EOR [Dloc] */ + GET_DLOC_L_IND_RD(); + EOR_INST(); + +inst48_SYM /* PHA */ +#ifdef ASM +# ifdef ACC8 + INC_KPC_1 + ldil l%dispatch,link + extru acc,31,8,arg0 + b push_8 + ldo r%dispatch(link),link +# else + INC_KPC_1 + ldil l%dispatch,link + extru acc,31,16,arg0 + b push_16 + ldo r%dispatch(link),link +# endif +#else + INC_KPC_1; +# ifdef ACC8 + PUSH8(acc); +# else + PUSH16(acc); +# endif +#endif + +inst49_SYM /* EOR #imm */ + GET_IMM_MEM(); + EOR_INST(); + +inst4a_SYM /* LSR a */ +#ifdef ASM +# ifdef ACC8 + extru acc,31,1,scratch2 + INC_KPC_1 + extru acc,30,7,zero + ldi 0,neg + dep scratch2,31,1,psr /* set carry */ + b dispatch + dep zero,31,8,acc +# else + extru acc,31,1,scratch2 + INC_KPC_1 + extru acc,30,15,zero + ldi 0,neg + dep scratch2,31,1,psr /* set carry */ + b dispatch + dep zero,31,16,acc +# endif +#else + INC_KPC_1; +# ifdef ACC8 + tmp1 = ((acc & 0xff) >> 1); + SET_CARRY8(acc << 8); + acc = (acc & 0xff00) + (tmp1 & 0xff); + SET_NEG_ZERO8(tmp1 & 0xff); +# else + tmp1 = (acc >> 1); + SET_CARRY8((acc << 8)); + acc = (tmp1 & 0xffff); + SET_NEG_ZERO16(acc); +# endif +#endif + +inst4b_SYM /* PHK */ +#ifdef ASM + ldil l%dispatch,link + extru kpc,15,8,arg0 + INC_KPC_1 + b push_8 + ldo r%dispatch(link),link +#else + PUSH8(kpc >> 16); + INC_KPC_1; +#endif + +inst4c_SYM /* JMP abs */ +#ifdef ASM + ldb 1(scratch1),scratch2 + CYCLES_PLUS_1 + ldb 2(scratch1),scratch1 + dep scratch2,31,8,kpc + b dispatch + dep scratch1,23,8,kpc +#else + GET_2BYTE_ARG; + CYCLES_PLUS_1; + kpc = (kpc & 0xff0000) + arg; +#endif + + +inst4d_SYM /* EOR abs */ + GET_ABS_RD(); + EOR_INST(); + +inst4e_SYM /* LSR abs */ + GET_ABS_RD(); + LSR_INST(0); + +inst4f_SYM /* EOR long */ + GET_LONG_RD(); + EOR_INST(); + + +inst50_SYM /* BVC disp8 */ +#ifdef ASM + COND_BR1 + bb,< psr,25,inst50_2_SYM + COND_BR2 + +inst50_2_SYM + COND_BR_UNTAKEN + +#else + BRANCH_DISP8((psr & 0x40) == 0); +#endif + +inst51_SYM /* EOR (Dloc),y */ + GET_DLOC_IND_Y_RD(); + EOR_INST(); + +inst52_SYM /* EOR (Dloc) */ + GET_DLOC_IND_RD(); + EOR_INST(); + +inst53_SYM /* EOR (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + EOR_INST(); + +inst54_SYM /* MVN */ +#ifdef ASM + ldb 2(scratch1),scratch2 /* src bank */ + bb,< psr,23,inst54_notnat_SYM + ldb 1(scratch1),dbank /* dest bank */ + bb,< psr,27,inst54_notnat_SYM + stw scratch2,STACK_SRC_BANK(sp) + +/* even in 8bit acc mode, use 16-bit accumulator! */ + +inst54_loop_SYM + CYCLES_PLUS_1 + ldw STACK_SRC_BANK(sp),scratch2 + copy xreg,arg0 + + bl get_mem_long_8,link + dep scratch2,15,8,arg0 +/* got byte */ + copy ret0,arg1 + copy yreg,arg0 + bl set_mem_long_8,link + dep dbank,15,8,arg0 +/* wrote byte, dec acc */ + CYCLES_PLUS_2 + fldds 0(fcycles_stop_ptr),fcycles_stop + addi 1,xreg,xreg + zdepi -1,31,16,scratch2 + addi 1,yreg,yreg + addi -1,acc,acc + fcmp,<,dbl fcycles,fcycles_stop + and xreg,scratch2,xreg + extrs acc,31,16,scratch1 + and yreg,scratch2,yreg + + comib,= -1,scratch1,inst54_done_SYM + and acc,scratch2,acc + ftest + b,n inst54_out_of_time_SYM + + CYCLES_PLUS_2 + b inst54_loop_SYM + nop + +/* get here if done */ +inst54_done_SYM + INC_KPC_3 + b dispatch + nop + +inst54_out_of_time_SYM +/* cycle have gone positive, just get out, don't update kpc */ + b,n dispatch + +inst54_notnat_SYM + copy dbank,ret0 + dep scratch2,23,8,ret0 + CYCLES_PLUS_3 + depi RET_MVN,3,4,ret0 + b dispatch_done + CYCLES_PLUS_3 +#else + GET_2BYTE_ARG; + /* arg & 0xff = dest bank, arg & 0xff00 = src bank */ + if(psr & 0x110) { + halt_printf("MVN but not native m or x!\n"); + break; + } + CYCLES_MINUS_2; + dbank = arg & 0xff; + tmp1 = (arg >> 8) & 0xff; + while(1) { + CYCLES_PLUS_3; + GET_MEMORY8((tmp1 << 16) + xreg, arg); + SET_MEMORY8((dbank << 16) + yreg, arg); + CYCLES_PLUS_2; + xreg = (xreg + 1) & 0xffff; + yreg = (yreg + 1) & 0xffff; + acc = (acc - 1) & 0xffff; + if(acc == 0xffff) { + INC_KPC_3; + break; + } + if(fcycles >= g_fcycles_stop) { + break; + } + } +#endif + +inst55_SYM /* EOR Dloc,x */ + GET_DLOC_X_RD(); + EOR_INST(); + +inst56_SYM /* LSR Dloc,X */ + GET_DLOC_X_RD(); + LSR_INST(1); + +inst57_SYM /* EOR [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + EOR_INST(); + +inst58_SYM /* CLI */ +#ifdef ASM + INC_KPC_1 + b check_irqs_pending /* check for ints pending! */ + depi 0,29,1,psr /* clear int disable */ +#else + psr = psr & (~4); + INC_KPC_1; + if(((psr & 0x4) == 0) && g_irq_pending) { + FINISH(RET_IRQ, 0); + } +#endif + +inst59_SYM /* EOR abs,y */ + GET_ABS_Y_RD(); + EOR_INST(); + +inst5a_SYM /* PHY */ +#ifdef ASM + INC_KPC_1 + ldil l%dispatch,link + bb,>= psr,27,phy_16_SYM + ldo r%dispatch(link),link + + b push_8 + copy yreg,arg0 + +phy_16_SYM + b push_16 + copy yreg,arg0 +#else + INC_KPC_1; + if(psr & 0x10) { + PUSH8(yreg); + } else { + PUSH16(yreg); + } +#endif + +inst5b_SYM /* TCD */ +#ifdef ASM + extru acc,31,16,direct + INC_KPC_1 + copy acc,zero + b dispatch + extru acc,16,1,neg +#else + INC_KPC_1; + direct = acc; + SET_NEG_ZERO16(acc); +#endif + +inst5c_SYM /* JMP Long */ +#ifdef ASM + ldb 1(scratch1),kpc + ldb 2(scratch1),scratch2 + CYCLES_PLUS_1 + ldb 3(scratch1),arg0 /* new bank */ + dep scratch2,23,8,kpc + b dispatch + dep arg0,15,8,kpc +#else + GET_3BYTE_ARG; + CYCLES_PLUS_1; + kpc = arg; +#endif + +inst5d_SYM /* EOR Abs,X */ + GET_ABS_X_RD(); + EOR_INST(); + +inst5e_SYM /* LSR Abs,X */ + GET_ABS_X_RD_WR(); + LSR_INST(0); + +inst5f_SYM /* EOR Long,X */ + GET_LONG_X_RD(); + EOR_INST(); + + +inst60_SYM /* RTS */ +#ifdef ASM + bl pull_16,link + CYCLES_PLUS_2 +/* ret0 is new kpc-1 */ + addi 1,ret0,ret0 + b dispatch + dep ret0,31,16,kpc +#else + CYCLES_PLUS_2 + PULL16(tmp1); + kpc = (kpc & 0xff0000) + ((tmp1 + 1) & 0xffff); +#endif + + +inst61_SYM /* ADC (Dloc,X) */ +/* called with arg = val to ADC in */ + GET_DLOC_X_IND_RD(); + ADC_INST(); + +inst62_SYM /* PER */ +#ifdef ASM + ldb 1(scratch1),ret0 + INC_KPC_3 + ldb 2(scratch1),scratch1 + CYCLES_PLUS_2 + ldil l%dispatch,link + dep scratch1,23,8,ret0 + ldo r%dispatch(link),link + add kpc,ret0,arg0 + b push_16_unsafe + extru arg0,31,16,arg0 +#else + GET_2BYTE_ARG; + CYCLES_PLUS_2; + INC_KPC_3; + PUSH16_UNSAFE(kpc + arg); +#endif + +inst63_SYM /* ADC Disp8,S */ +/* called with arg = val to ADC in */ + GET_DISP8_S_RD(); + ADC_INST(); + +inst64_SYM /* STZ Dloc */ + GET_DLOC_ADDR(); + STZ_INST(1); + +inst65_SYM /* ADC Dloc */ +/* called with arg = val to ADC in */ + GET_DLOC_RD(); + ADC_INST(); + +inst66_SYM /* ROR Dloc */ + GET_DLOC_RD(); +/* save1 is now apple addr */ +/* ret0 is data */ + ROR_INST(1); + +inst67_SYM /* ADC [Dloc] */ + GET_DLOC_L_IND_RD(); + ADC_INST(); + +inst68_SYM /* PLA */ +#ifdef ASM +# ifdef ACC8 + INC_KPC_1 + bl pull_8,link + CYCLES_PLUS_1 + extru ret0,31,8,zero + extru ret0,24,1,neg + b dispatch + dep ret0,31,8,acc +# else + INC_KPC_1 + bl pull_16,link + CYCLES_PLUS_1 + + extru ret0,31,16,zero + extru ret0,16,1,neg + b dispatch + extru ret0,31,16,acc +# endif +#else + INC_KPC_1; + CYCLES_PLUS_1; +# ifdef ACC8 + PULL8(tmp1); + acc = (acc & 0xff00) + tmp1; + SET_NEG_ZERO8(tmp1); +# else + PULL16(tmp1); + acc = tmp1; + SET_NEG_ZERO16(tmp1); +# endif +#endif + + +inst69_SYM /* ADC #imm */ + GET_IMM_MEM(); + ADC_INST(); + +inst6a_SYM /* ROR a */ +#ifdef ASM +# ifdef ACC8 + extru psr,31,1,neg + INC_KPC_1 + extru acc,30,7,zero + dep neg,24,1,zero + dep acc,31,1,psr /* set carry */ + b dispatch + dep zero,31,8,acc +# else + extru psr,31,1,neg + INC_KPC_1 + extru acc,30,15,zero + dep neg,16,1,zero + dep acc,31,1,psr /* set carry */ + b dispatch + dep zero,31,16,acc +# endif +#else + INC_KPC_1; +# ifdef ACC8 + tmp1 = ((acc & 0xff) >> 1) + ((psr & 1) << 7); + SET_CARRY8((acc << 8)); + acc = (acc & 0xff00) + (tmp1 & 0xff); + SET_NEG_ZERO8(tmp1 & 0xff); +# else + tmp1 = (acc >> 1) + ((psr & 1) << 15); + SET_CARRY16((acc << 16)); + acc = (tmp1 & 0xffff); + SET_NEG_ZERO16(acc); +# endif +#endif + +inst6b_SYM /* RTL */ +#ifdef ASM + bl pull_24,link + CYCLES_PLUS_1 +/* ret0 is new kpc-1 */ + copy ret0,kpc + addi 1,ret0,scratch1 + b dispatch + dep scratch1,31,16,kpc + +#else + CYCLES_PLUS_1; + PULL24(tmp1); + kpc = (tmp1 & 0xff0000) + ((tmp1 + 1) & 0xffff); +#endif + +inst6c_SYM /* JMP (abs) */ +#ifdef ASM + ldb 1(scratch1),arg0 + CYCLES_PLUS_1 + ldb 2(scratch1),scratch1 + bl get_mem_long_16,link + dep scratch1,23,8,arg0 +/* ret0 is addr to jump to */ + b dispatch + dep ret0,31,16,kpc +#else + GET_2BYTE_ARG; + CYCLES_PLUS_1; + GET_MEMORY16(arg, tmp1, 1); + kpc = (kpc & 0xff0000) + tmp1; +#endif + +inst6d_SYM /* ADC abs */ + GET_ABS_RD(); + ADC_INST(); + +inst6e_SYM /* ROR abs */ + GET_ABS_RD(); + ROR_INST(0); + +inst6f_SYM /* ADC long */ + GET_LONG_RD(); + ADC_INST(); + + +inst70_SYM /* BVS disp8 */ +#ifdef ASM + COND_BR1 + bb,>= psr,25,inst70_2_SYM + COND_BR2 + +inst70_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8((psr & 0x40)); +#endif + +inst71_SYM /* ADC (Dloc),y */ + GET_DLOC_IND_Y_RD(); + ADC_INST(); + +inst72_SYM /* ADC (Dloc) */ + GET_DLOC_IND_RD(); + ADC_INST(); + +inst73_SYM /* ADC (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + ADC_INST(); + +inst74_SYM /* STZ Dloc,x */ +#ifdef ASM + ldb 1(scratch1),arg0 + GET_DLOC_X_WR(); + STZ_INST(1); +#else + GET_1BYTE_ARG; + GET_DLOC_X_WR(); + STZ_INST(1); +#endif + +inst75_SYM /* ADC Dloc,x */ + GET_DLOC_X_RD(); + ADC_INST(); + +inst76_SYM /* ROR Dloc,X */ + GET_DLOC_X_RD(); + ROR_INST(1); + +inst77_SYM /* ADC [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + ADC_INST(); + +inst78_SYM /* SEI */ +#ifdef ASM + INC_KPC_1 + b dispatch + depi 1,29,1,psr /* set int disable */ +#else + psr = psr | 4; + INC_KPC_1; +#endif + +inst79_SYM /* ADC abs,y */ + GET_ABS_Y_RD(); + ADC_INST(); + +inst7a_SYM /* PLY */ +#ifdef ASM + INC_KPC_1 + bb,>= psr,27,inst7a_16bit_SYM + nop + + bl pull_8,link + CYCLES_PLUS_1 + + extru ret0,31,8,zero + extru ret0,24,1,neg + b dispatch + copy zero,yreg + +inst7a_16bit_SYM + bl pull_16,link + CYCLES_PLUS_1 + + extru ret0,31,16,zero + extru ret0,16,1,neg + b dispatch + copy zero,yreg + +#else + INC_KPC_1; + CYCLES_PLUS_1 + if(psr & 0x10) { + PULL8(yreg); + SET_NEG_ZERO8(yreg); + } else { + PULL16(yreg); + SET_NEG_ZERO16(yreg); + } +#endif + +inst7b_SYM /* TDC */ +#ifdef ASM + extru direct,31,16,zero + copy direct,acc + INC_KPC_1 + b dispatch + extru direct,16,1,neg +#else + INC_KPC_1; + acc = direct; + SET_NEG_ZERO16(direct); +#endif + +inst7c_SYM /* JMP (Abs,x) */ +/* always access kbank, xreg cannot wrap into next bank */ +#ifdef ASM + ldb 1(scratch1),ret0 + copy kpc,scratch2 + ldb 2(scratch1),scratch1 + dep xreg,31,16,scratch2 + CYCLES_PLUS_2 + dep scratch1,23,8,ret0 + add ret0,scratch2,arg0 + bl get_mem_long_16,link + extru arg0,31,24,arg0 + b dispatch + dep ret0,31,16,kpc +#else + GET_2BYTE_ARG; + arg = (kpc & 0xff0000) + ((xreg + arg) & 0xffff); + CYCLES_PLUS_2; + GET_MEMORY16(arg, tmp1, 1); + kpc = (kpc & 0xff0000) + tmp1; +#endif + +inst7d_SYM /* ADC Abs,X */ + GET_ABS_X_RD(); + ADC_INST(); + +inst7e_SYM /* ROR Abs,X */ + GET_ABS_X_RD_WR(); + ROR_INST(0); + +inst7f_SYM /* ADC Long,X */ + GET_LONG_X_RD(); + ADC_INST(); + + +inst80_SYM /* BRA */ +#ifdef ASM + COND_BR1 + COND_BR2 +#else + BRANCH_DISP8(1); +#endif + + +inst81_SYM /* STA (Dloc,X) */ + GET_DLOC_X_IND_ADDR(); + STA_INST(0); + +inst82_SYM /* BRL disp16 */ +#ifdef ASM + ldb 1(scratch1),ret0 + CYCLES_PLUS_1 + ldb 2(scratch1),scratch1 + addi 3,kpc,scratch2 + dep scratch1,23,8,ret0 + add ret0,scratch2,scratch2 + b dispatch + dep scratch2,31,16,kpc +#else + GET_2BYTE_ARG; + CYCLES_PLUS_1; + kpc = (kpc & 0xff0000) + ((kpc + 3 + arg) & 0xffff); +#endif + +inst83_SYM /* STA Disp8,S */ + GET_DISP8_S_ADDR(); + STA_INST(1); + +inst84_SYM /* STY Dloc */ + GET_DLOC_ADDR(); + STY_INST(1); + + +inst85_SYM /* STA Dloc */ + GET_DLOC_ADDR(); + STA_INST(1); + +inst86_SYM /* STX Dloc */ + GET_DLOC_ADDR(); + STX_INST(1); + + +inst87_SYM /* STA [Dloc] */ + GET_DLOC_L_IND_ADDR(); + STA_INST(0); + +inst88_SYM /* DEY */ +#ifdef ASM + INC_KPC_1 + bb,< psr,27,inst88_8bit_SYM + addi -1,yreg,yreg +/* 16 bit */ + extru yreg,31,16,zero + extru yreg,16,1,neg + b dispatch + copy zero,yreg + +inst88_8bit_SYM + extru yreg,31,8,zero + extru yreg,24,1,neg + b dispatch + copy zero,yreg +#else + INC_KPC_1; + SET_INDEX_REG(yreg - 1, yreg); +#endif + +inst89_SYM /* BIT #imm */ +#ifdef ASM + GET_IMM_MEM(); +# ifdef ACC8 +/* Immediate BIT does not set condition flags */ + and acc,ret0,zero + b dispatch + extru zero,31,8,zero +# else + and acc,ret0,zero + b dispatch + extru zero,31,16,zero +# endif +#else + GET_IMM_MEM(); +# ifdef ACC8 + zero = (acc & arg) & 0xff; +# else + zero = (acc & arg) & 0xffff; +# endif +#endif + +inst8a_SYM /* TXA */ +#ifdef ASM +# ifdef ACC8 + extru xreg,31,8,zero + INC_KPC_1 + extru xreg,24,1,neg + b dispatch + dep zero,31,8,acc +# else + extru xreg,31,16,zero + INC_KPC_1 + extru xreg,16,1,neg + b dispatch + zdep zero,31,16,acc +# endif +#else + INC_KPC_1; + arg = xreg; + LDA_INST(); +#endif + +inst8b_SYM /* PHB */ +#ifdef ASM + ldil l%dispatch,link + extru dbank,31,8,arg0 + INC_KPC_1 + b push_8 + ldo r%dispatch(link),link +#else + INC_KPC_1; + PUSH8(dbank); +#endif + +inst8c_SYM /* STY abs */ + GET_ABS_ADDR(); + STY_INST(0); + +inst8d_SYM /* STA abs */ + GET_ABS_ADDR(); + STA_INST(0); + +inst8e_SYM /* STX abs */ + GET_ABS_ADDR(); + STX_INST(0); + + +inst8f_SYM /* STA long */ + GET_LONG_ADDR(); + STA_INST(0); + + +inst90_SYM /* BCC disp8 */ +#ifdef ASM + COND_BR1 + bb,< psr,31,inst90_2_SYM + COND_BR2 + +inst90_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8((psr & 0x01) == 0); +#endif + + +inst91_SYM /* STA (Dloc),y */ + GET_DLOC_IND_Y_ADDR_FOR_WR(); + STA_INST(0); + +inst92_SYM /* STA (Dloc) */ + GET_DLOC_IND_ADDR(); + STA_INST(0); + +inst93_SYM /* STA (Disp8,s),y */ + GET_DISP8_S_IND_Y_ADDR(); + STA_INST(0); + +inst94_SYM /* STY Dloc,x */ + GET_DLOC_X_ADDR(); + STY_INST(1); + +inst95_SYM /* STA Dloc,x */ + GET_DLOC_X_ADDR(); + STA_INST(1); + +inst96_SYM /* STX Dloc,Y */ + GET_DLOC_Y_ADDR(); + STX_INST(1); + +inst97_SYM /* STA [Dloc],Y */ + GET_DLOC_L_IND_Y_ADDR(); + STA_INST(0); + +inst98_SYM /* TYA */ +#ifdef ASM +# ifdef ACC8 + extru yreg,31,8,zero + INC_KPC_1 + extru yreg,24,1,neg + b dispatch + dep zero,31,8,acc +# else + extru yreg,31,16,zero + INC_KPC_1 + extru yreg,16,1,neg + b dispatch + zdep zero,31,16,acc +# endif +#else + INC_KPC_1; + arg = yreg; + LDA_INST(); +#endif + +inst99_SYM /* STA abs,y */ + GET_ABS_INDEX_ADDR_FOR_WR(yreg) + STA_INST(0); + +inst9a_SYM /* TXS */ +#ifdef ASM + copy xreg,stack + extru,= psr,23,1,0 + depi 1,23,24,stack + INC_KPC_1 + b dispatch + nop +#else + stack = xreg; + if(psr & 0x100) { + stack = 0x100 | (stack & 0xff); + } + INC_KPC_1; +#endif + + +inst9b_SYM /* TXY */ +#ifdef ASM + extru xreg,24,1,neg + INC_KPC_1 + extru,<> psr,27,1,0 ;skip next if 8bit + extru xreg,16,1,neg + copy xreg,yreg + b dispatch + copy xreg,zero +#else + SET_INDEX_REG(xreg, yreg); + INC_KPC_1; +#endif + + +inst9c_SYM /* STZ Abs */ + GET_ABS_ADDR(); + STZ_INST(0); + +inst9d_SYM /* STA Abs,X */ + GET_ABS_INDEX_ADDR_FOR_WR(xreg); + STA_INST(0); + +inst9e_SYM /* STZ Abs,X */ + GET_ABS_INDEX_ADDR_FOR_WR(xreg); + STZ_INST(0); + +inst9f_SYM /* STA Long,X */ + GET_LONG_X_ADDR_FOR_WR(); + STA_INST(0); + + +insta0_SYM /* LDY #imm */ +#ifdef ASM + INC_KPC_2 + bb,>= psr,27,insta0_16bit_SYM + ldb 1(scratch1),zero + + extru zero,24,1,neg + b dispatch + copy zero,yreg +insta0_16bit_SYM + ldb 2(scratch1),scratch1 + INC_KPC_1 + CYCLES_PLUS_1 + extru scratch1,24,1,neg + dep scratch1,23,8,zero + b dispatch + copy zero,yreg +#else + INC_KPC_2; + if((psr & 0x10) == 0) { + GET_2BYTE_ARG; + CYCLES_PLUS_1 + INC_KPC_1; + } else { + GET_1BYTE_ARG; + } + SET_INDEX_REG(arg, yreg); +#endif + + +insta1_SYM /* LDA (Dloc,X) */ +/* called with arg = val to LDA in */ + GET_DLOC_X_IND_RD(); + LDA_INST(); + +insta2_SYM /* LDX #imm */ +#ifdef ASM + ldb 1(scratch1),zero + bb,>= psr,27,insta2_16bit_SYM + INC_KPC_2; + + extru zero,24,1,neg + b dispatch + copy zero,xreg +insta2_16bit_SYM + ldb 2(scratch1),scratch1 + INC_KPC_1 + CYCLES_PLUS_1 + extru scratch1,24,1,neg + dep scratch1,23,8,zero + b dispatch + copy zero,xreg +#else + INC_KPC_2; + if((psr & 0x10) == 0) { + GET_2BYTE_ARG; + CYCLES_PLUS_1 + INC_KPC_1; + } else { + GET_1BYTE_ARG; + } + SET_INDEX_REG(arg, xreg); +#endif + +insta3_SYM /* LDA Disp8,S */ +/* called with arg = val to LDA in */ + GET_DISP8_S_RD(); + LDA_INST(); + +insta4_SYM /* LDY Dloc */ +#ifdef ASM + ldb 1(scratch1),arg0 + GET_DLOC_WR() + b get_yreg_from_mem + nop +#else + C_LDY_DLOC(); +#endif + +insta5_SYM /* LDA Dloc */ +/* called with arg = val to LDA in */ + GET_DLOC_RD(); + LDA_INST(); + +insta6_SYM /* LDX Dloc */ +#ifdef ASM + ldb 1(scratch1),arg0 + GET_DLOC_WR() + b get_xreg_from_mem + nop +#else + C_LDX_DLOC(); +#endif + +insta7_SYM /* LDA [Dloc] */ + GET_DLOC_L_IND_RD(); + LDA_INST(); + +insta8_SYM /* TAY */ +#ifdef ASM + INC_KPC_1 + bb,>= psr,27,insta8_16bit_SYM + extru acc,31,8,zero + + extru acc,24,1,neg + b dispatch + copy zero,yreg + +insta8_16bit_SYM + extru acc,31,16,zero + extru acc,16,1,neg + b dispatch + copy zero,yreg +#else + INC_KPC_1; + SET_INDEX_REG(acc, yreg); +#endif + +insta9_SYM /* LDA #imm */ + GET_IMM_MEM(); + LDA_INST(); + +instaa_SYM /* TAX */ +#ifdef ASM + INC_KPC_1 + bb,>= psr,27,instaa_16bit_SYM + extru acc,31,8,zero + + extru acc,24,1,neg + b dispatch + copy zero,xreg + +instaa_16bit_SYM + extru acc,31,16,zero + extru acc,16,1,neg + b dispatch + copy zero,xreg +#else + INC_KPC_1; + SET_INDEX_REG(acc, xreg); +#endif + +instab_SYM /* PLB */ +#ifdef ASM + INC_KPC_1 + bl pull_8,link + CYCLES_PLUS_1 + + extru ret0,31,8,zero + extru ret0,24,1,neg + b dispatch + copy zero,dbank +#else + INC_KPC_1; + CYCLES_PLUS_1 + PULL8(dbank); + SET_NEG_ZERO8(dbank); +#endif + +instac_SYM /* LDY abs */ +#ifdef ASM + GET_ABS_ADDR() + b get_yreg_from_mem + nop +#else + C_LDY_ABS(); +#endif + + +instad_SYM /* LDA abs */ + GET_ABS_RD(); + LDA_INST(); + +instae_SYM /* LDX abs */ +#ifdef ASM + GET_ABS_ADDR() + b get_xreg_from_mem + nop +#else + C_LDX_ABS(); +#endif + +instaf_SYM /* LDA long */ + GET_LONG_RD(); + LDA_INST(); + + +instb0_SYM /* BCS disp8 */ +#ifdef ASM + COND_BR1 + bb,>= psr,31,instb0_2_SYM + COND_BR2 + +instb0_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8((psr & 0x01)); +#endif + +instb1_SYM /* LDA (Dloc),y */ + GET_DLOC_IND_Y_RD(); + LDA_INST(); + +instb2_SYM /* LDA (Dloc) */ + GET_DLOC_IND_RD(); + LDA_INST(); + +instb3_SYM /* LDA (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + LDA_INST(); + +instb4_SYM /* LDY Dloc,x */ +#ifdef ASM + ldb 1(scratch1),arg0 + GET_DLOC_X_WR(); + b get_yreg_from_mem + nop +#else + C_LDY_DLOC_X(); +#endif + +instb5_SYM /* LDA Dloc,x */ + GET_DLOC_X_RD(); + LDA_INST(); + +instb6_SYM /* LDX Dloc,y */ +#ifdef ASM + ldb 1(scratch1),arg0 + GET_DLOC_Y_WR(); + b get_xreg_from_mem + nop +#else + C_LDX_DLOC_Y(); +#endif + +instb7_SYM /* LDA [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + LDA_INST(); + +instb8_SYM /* CLV */ +#ifdef ASM + INC_KPC_1 + b dispatch + depi 0,25,1,psr /* clear overflow */ +#else + psr = psr & ~0x40; + INC_KPC_1; +#endif + +instb9_SYM /* LDA abs,y */ + GET_ABS_Y_RD(); + LDA_INST(); + +instba_SYM /* TSX */ +#ifdef ASM + INC_KPC_1 + bb,>= psr,27,instba_16bit_SYM + extru stack,31,8,zero + + extru stack,24,1,neg + b dispatch + copy zero,xreg +instba_16bit_SYM + copy stack,zero + extru stack,16,1,neg + b dispatch + copy zero,xreg +#else + INC_KPC_1; + SET_INDEX_REG(stack, xreg); +#endif + +instbb_SYM /* TYX */ +#ifdef ASM + INC_KPC_1 + bb,>= psr,27,instbb_16bit_SYM + copy yreg,xreg + +/* 8 bit */ + extru yreg,24,1,neg + b dispatch + copy yreg,zero +instbb_16bit_SYM + extru yreg,16,1,neg + b dispatch + copy yreg,zero +#else + INC_KPC_1; + SET_INDEX_REG(yreg, xreg); +#endif + +instbc_SYM /* LDY Abs,X */ +#ifdef ASM + GET_ABS_INDEX_ADDR_FOR_RD(xreg) + b get_yreg_from_mem + nop +#else + C_LDY_ABS_X(); +#endif + +instbd_SYM /* LDA Abs,X */ + GET_ABS_X_RD(); + LDA_INST(); + +instbe_SYM /* LDX Abs,y */ +#ifdef ASM + GET_ABS_INDEX_ADDR_FOR_RD(yreg) + b get_xreg_from_mem + nop +#else + C_LDX_ABS_Y(); +#endif + +instbf_SYM /* LDA Long,X */ + GET_LONG_X_RD(); + LDA_INST(); + + +instc0_SYM /* CPY #imm */ +#ifdef ASM + ldb 1(scratch1),ret0 + bb,>= psr,27,instc0_16bit_SYM + INC_KPC_2; + CMP_INDEX_REG_MEAT8(yreg) +instc0_16bit_SYM + ldb 2(scratch1),scratch1 + CYCLES_PLUS_1 + INC_KPC_1 + dep scratch1,23,8,ret0 + CMP_INDEX_REG_MEAT16(yreg) +#else + C_CPY_IMM(); +#endif + + +instc1_SYM /* CMP (Dloc,X) */ +/* called with arg = val to CMP in */ + GET_DLOC_X_IND_RD(); + CMP_INST(); + +instc2_SYM /* REP #imm */ +#ifdef ASM + ldb 1(scratch1),ret0 + extru psr,27,2,arg0 /* save old x & m */ + INC_KPC_2; + dep neg,24,1,psr + CYCLES_PLUS_1 + depi 0,30,1,psr + comiclr,<> 0,zero,0 + depi 1,30,1,psr + andcm psr,ret0,ret0 + ldi 0,zero + extru,<> ret0,30,1,0 + ldi 1,zero + dep ret0,31,8,psr + b update_system_state + extru ret0,24,1,neg +#else + GET_1BYTE_ARG; + tmp2 = psr; + CYCLES_PLUS_1; + INC_KPC_2; + psr = (psr & ~0x82) | ((neg & 1) << 7) | ((!zero) << 1); + psr = psr & ~(arg & 0xff); + zero = !(psr & 2); + neg = (psr >> 7) & 1; + UPDATE_PSR(psr, tmp2); +#endif + + +instc3_SYM /* CMP Disp8,S */ +/* called with arg = val to CMP in */ + GET_DISP8_S_RD(); + CMP_INST(); + +instc4_SYM /* CPY Dloc */ +#ifdef ASM + GET_DLOC_ADDR() + CMP_INDEX_REG_LOAD(instc4_16bit_SYM, yreg) +#else + C_CPY_DLOC(); +#endif + + +instc5_SYM /* CMP Dloc */ + GET_DLOC_RD(); + CMP_INST(); + +instc6_SYM /* DEC Dloc */ + GET_DLOC_RD(); + DEC_INST(1); + +instc7_SYM /* CMP [Dloc] */ + GET_DLOC_L_IND_RD(); + CMP_INST(); + +instc8_SYM /* INY */ +#ifdef ASM + INC_KPC_1 + addi 1,yreg,yreg + bb,>= psr,27,instc8_16bit_SYM + extru yreg,31,8,zero + + extru yreg,24,1,neg + b dispatch + copy zero,yreg + +instc8_16bit_SYM + extru yreg,31,16,zero + extru yreg,16,1,neg + b dispatch + copy zero,yreg +#else + INC_KPC_1; + SET_INDEX_REG(yreg + 1, yreg); +#endif + +instc9_SYM /* CMP #imm */ + GET_IMM_MEM(); + CMP_INST(); + +instca_SYM /* DEX */ +#ifdef ASM + INC_KPC_1 + addi -1,xreg,xreg + bb,>= psr,27,instca_16bit_SYM + extru xreg,31,8,zero + + extru xreg,24,1,neg + b dispatch + copy zero,xreg + +instca_16bit_SYM + extru xreg,31,16,zero + extru xreg,16,1,neg + b dispatch + copy zero,xreg +#else + INC_KPC_1; + SET_INDEX_REG(xreg - 1, xreg); +#endif + +instcb_SYM /* WAI */ +#ifdef ASM + ldil l%g_wait_pending,scratch1 + CYCLES_FINISH + ldi 1,scratch2 + b dispatch + stw scratch2,r%g_wait_pending(scratch1) +#else + g_wait_pending = 1; + CYCLES_FINISH +#endif + +instcc_SYM /* CPY abs */ +#ifdef ASM + GET_ABS_ADDR() + CMP_INDEX_REG_LOAD(instcc_16bit_SYM, yreg) +#else + C_CPY_ABS(); +#endif + + + + +instcd_SYM /* CMP abs */ + GET_ABS_RD(); + CMP_INST(); + +instce_SYM /* DEC abs */ + GET_ABS_RD(); + DEC_INST(0); + + +instcf_SYM /* CMP long */ + GET_LONG_RD(); + CMP_INST(); + + +instd0_SYM /* BNE disp8 */ +#ifdef ASM + COND_BR1 + comib,= 0,zero,instd0_2_SYM + COND_BR2 + +instd0_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8(zero != 0); +#endif + +instd1_SYM /* CMP (Dloc),y */ + GET_DLOC_IND_Y_RD(); + CMP_INST(); + +instd2_SYM /* CMP (Dloc) */ + GET_DLOC_IND_RD(); + CMP_INST(); + +instd3_SYM /* CMP (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + CMP_INST(); + +instd4_SYM /* PEI Dloc */ +#ifdef ASM + GET_DLOC_ADDR() + bl get_mem_long_16,link + CYCLES_PLUS_1 + +/* push ret0 */ + extru ret0,31,16,arg0 + ldil l%dispatch,link + b push_16_unsafe + ldo r%dispatch(link),link +#else + GET_DLOC_ADDR() + GET_MEMORY16(arg, arg, 1); + CYCLES_PLUS_1; + PUSH16_UNSAFE(arg); +#endif + +instd5_SYM /* CMP Dloc,x */ + GET_DLOC_X_RD(); + CMP_INST(); + +instd6_SYM /* DEC Dloc,x */ + GET_DLOC_X_RD(); + DEC_INST(1); + +instd7_SYM /* CMP [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + CMP_INST(); + +instd8_SYM /* CLD */ +#ifdef ASM + INC_KPC_1 + b dispatch + depi 0,28,1,psr /* clear decimal */ +#else + psr = psr & (~0x8); + INC_KPC_1; +#endif + +instd9_SYM /* CMP abs,y */ + GET_ABS_Y_RD(); + CMP_INST(); + +instda_SYM /* PHX */ +#ifdef ASM + INC_KPC_1 + bb,>= psr,27,instda_16bit_SYM + ldil l%dispatch,link + + extru xreg,31,8,arg0 + b push_8 + ldo r%dispatch(link),link + +instda_16bit_SYM + extru xreg,31,16,arg0 + b push_16 + ldo r%dispatch(link),link +#else + INC_KPC_1; + if(psr & 0x10) { + PUSH8(xreg); + } else { + PUSH16(xreg); + } +#endif + +instdb_SYM /* STP */ +#ifdef ASM + ldb 1(scratch1),ret0 + CYCLES_PLUS_1 + b dispatch_done + depi RET_STP,3,4,ret0 +#else + GET_1BYTE_ARG; + CYCLES_PLUS_1 + FINISH(RET_STP, arg); +#endif + +instdc_SYM /* JML (Abs) */ +#ifdef ASM + ldb 1(scratch1),arg0 + ldb 2(scratch1),scratch1 + CYCLES_PLUS_1 + bl get_mem_long_24,link + dep scratch1,23,8,arg0 + + b dispatch + copy ret0,kpc +#else + GET_2BYTE_ARG; + CYCLES_PLUS_1; + GET_MEMORY24(arg, kpc, 1); +#endif + +instdd_SYM /* CMP Abs,X */ + GET_ABS_X_RD(); + CMP_INST(); + +instde_SYM /* DEC Abs,X */ + GET_ABS_X_RD_WR(); + DEC_INST(0); + +instdf_SYM /* CMP Long,X */ + GET_LONG_X_RD(); + CMP_INST(); + + +inste0_SYM /* CPX #imm */ +#ifdef ASM + ldb 1(scratch1),ret0 + bb,>= psr,27,inste0_16bit_SYM + INC_KPC_2; + CMP_INDEX_REG_MEAT8(xreg) +inste0_16bit_SYM + ldb 2(scratch1),scratch1 + CYCLES_PLUS_1 + INC_KPC_1 + dep scratch1,23,8,ret0 + CMP_INDEX_REG_MEAT16(xreg) +#else + C_CPX_IMM(); +#endif + + +inste1_SYM /* SBC (Dloc,X) */ +/* called with arg = val to SBC in */ + GET_DLOC_X_IND_RD(); + SBC_INST(); + +inste2_SYM /* SEP #imm */ +#ifdef ASM + ldb 1(scratch1),ret0 + extru psr,27,2,arg0 /* save old x & m */ + INC_KPC_2; + dep neg,24,1,psr + CYCLES_PLUS_1 + depi 0,30,1,psr + comiclr,<> 0,zero,0 + depi 1,30,1,psr + or psr,ret0,ret0 + ldi 0,zero + extru,<> ret0,30,1,0 + ldi 1,zero + dep ret0,31,8,psr + b update_system_state + extru ret0,24,1,neg +#else + GET_1BYTE_ARG; + tmp2 = psr; + CYCLES_PLUS_1; + INC_KPC_2; + psr = (psr & ~0x82) | ((neg & 1) << 7) | ((!zero) << 1); + psr = psr | (arg & 0xff); + zero = !(psr & 2); + neg = (psr >> 7) & 1; + UPDATE_PSR(psr, tmp2); +#endif + + +inste3_SYM /* SBC Disp8,S */ +/* called with arg = val to SBC in */ + GET_DISP8_S_RD(); + SBC_INST(); + +inste4_SYM /* CPX Dloc */ +#ifdef ASM + GET_DLOC_ADDR() + CMP_INDEX_REG_LOAD(inste4_16bit_SYM, xreg) +#else + C_CPX_DLOC(); +#endif + + +inste5_SYM /* SBC Dloc */ +/* called with arg = val to SBC in */ + GET_DLOC_RD(); + SBC_INST(); + +inste6_SYM /* INC Dloc */ + GET_DLOC_RD(); + INC_INST(1); + +inste7_SYM /* SBC [Dloc] */ + GET_DLOC_L_IND_RD(); + SBC_INST(); + +inste8_SYM /* INX */ +#ifdef ASM + INC_KPC_1 + addi 1,xreg,xreg + bb,>= psr,27,inste8_16bit_SYM + extru xreg,31,8,zero + + extru xreg,24,1,neg + b dispatch + copy zero,xreg + +inste8_16bit_SYM + extru xreg,31,16,zero + extru xreg,16,1,neg + b dispatch + copy zero,xreg +#else + INC_KPC_1; + SET_INDEX_REG(xreg + 1, xreg); +#endif + +inste9_SYM /* SBC #imm */ + GET_IMM_MEM(); + SBC_INST(); + +instea_SYM /* NOP */ +#ifdef ASM + INC_KPC_1 + b dispatch + nop +#else + INC_KPC_1; +#endif + +insteb_SYM /* XBA */ +#ifdef ASM + extru acc,16,1,neg /* Z and N reflect status of low 8 */ + CYCLES_PLUS_1 /* bits of final acc value! */ + copy acc,scratch1 /* regardlessof ACC 8 or 16 bit */ + extru acc,23,8,acc + INC_KPC_1 + copy acc,zero + b dispatch + dep scratch1,23,8,acc +#else + tmp1 = acc & 0xff; + CYCLES_PLUS_1 + acc = (tmp1 << 8) + (acc >> 8); + INC_KPC_1; + SET_NEG_ZERO8(acc & 0xff); +#endif + +instec_SYM /* CPX abs */ +#ifdef ASM + GET_ABS_ADDR() + CMP_INDEX_REG_LOAD(instec_16bit_SYM, xreg) +#else + C_CPX_ABS(); +#endif + + + + +insted_SYM /* SBC abs */ + GET_ABS_RD(); + SBC_INST(); + +instee_SYM /* INC abs */ + GET_ABS_RD(); + INC_INST(0); + + +instef_SYM /* SBC long */ + GET_LONG_RD(); + SBC_INST(); + + +instf0_SYM /* BEQ disp8 */ +#ifdef ASM + COND_BR1 + comib,<> 0,zero,instf0_2_SYM + COND_BR2 + +instf0_2_SYM + COND_BR_UNTAKEN +#else + BRANCH_DISP8(zero == 0); +#endif + +instf1_SYM /* SBC (Dloc),y */ + GET_DLOC_IND_Y_RD(); + SBC_INST(); + +instf2_SYM /* SBC (Dloc) */ + GET_DLOC_IND_RD(); + SBC_INST(); + +instf3_SYM /* SBC (Disp8,s),y */ + GET_DISP8_S_IND_Y_RD(); + SBC_INST(); + +instf4_SYM /* PEA Abs */ +#ifdef ASM + ldb 1(scratch1),arg0 + ldil l%dispatch,link + ldb 2(scratch1),scratch1 + INC_KPC_3 + CYCLES_PLUS_1 + ldo r%dispatch(link),link + b push_16_unsafe + dep scratch1,23,8,arg0 +#else + GET_2BYTE_ARG; + CYCLES_PLUS_1; + INC_KPC_3; + PUSH16_UNSAFE(arg); +#endif + +instf5_SYM /* SBC Dloc,x */ + GET_DLOC_X_RD(); + SBC_INST(); + +instf6_SYM /* INC Dloc,x */ + GET_DLOC_X_RD(); + INC_INST(1); + +instf7_SYM /* SBC [Dloc],Y */ + GET_DLOC_L_IND_Y_RD(); + SBC_INST(); + +instf8_SYM /* SED */ +#ifdef ASM + INC_KPC_1 + b dispatch + depi 1,28,1,psr /* set decimal */ +#else + INC_KPC_1; + psr |= 0x8; +#endif + +instf9_SYM /* SBC abs,y */ + GET_ABS_Y_RD(); + SBC_INST(); + +instfa_SYM /* PLX */ +#ifdef ASM + bb,< psr,27,instfa_8bit_SYM + CYCLES_PLUS_1 + + INC_KPC_1 + bl pull_16,link + nop + + extru ret0,31,16,zero + extru ret0,16,1,neg + b dispatch + copy zero,xreg + +instfa_8bit_SYM + INC_KPC_1 + bl pull_8,link + nop + + extru ret0,31,8,zero + extru ret0,24,1,neg + b dispatch + copy zero,xreg +#else + INC_KPC_1; + CYCLES_PLUS_1; + if(psr & 0x10) { + PULL8(xreg); + SET_NEG_ZERO8(xreg); + } else { + PULL16(xreg); + SET_NEG_ZERO16(xreg); + } +#endif + +instfb_SYM /* XCE */ +#ifdef ASM + extru psr,27,2,arg0 /* save old x & m */ + INC_KPC_1 + extru psr,23,1,scratch1 /* e bit */ + dep psr,23,1,psr /* copy carry to e bit */ + b update_system_state + dep scratch1,31,1,psr /* copy e bit to carry */ +#else + tmp2 = psr; + INC_KPC_1; + psr = (tmp2 & 0xfe) | ((tmp2 & 1) << 8) | ((tmp2 >> 8) & 1); + UPDATE_PSR(psr, tmp2); +#endif + +instfc_SYM /* JSR (Abs,X) */ +#ifdef ASM + ldb 1(scratch1),ret0 + extru kpc,15,8,scratch2 + ldb 2(scratch1),scratch1 + dep scratch2,15,16,ret0 + INC_KPC_2; + dep scratch1,23,8,ret0 + add xreg,ret0,arg0 + bl get_mem_long_16,link + extru arg0,31,24,arg0 + + CYCLES_PLUS_2 + extru kpc,31,16,arg0 + ldil l%dispatch,link + dep ret0,31,16,kpc + b push_16_unsafe + ldo r%dispatch(link),link +#else + GET_2BYTE_ARG; + INC_KPC_2; + tmp1 = kpc; + arg = (kpc & 0xff0000) + ((arg + xreg) & 0xffff); + GET_MEMORY16(arg, tmp2, 1); + kpc = (kpc & 0xff0000) + tmp2; + CYCLES_PLUS_2 + PUSH16_UNSAFE(tmp1); +#endif + +instfd_SYM /* SBC Abs,X */ + GET_ABS_X_RD(); + SBC_INST(); + +instfe_SYM /* INC Abs,X */ + GET_ABS_X_RD_WR(); + INC_INST(0); + +instff_SYM /* SBC Long,X */ + GET_LONG_X_RD(); + SBC_INST(); + diff --git a/src/iwm.c b/src/iwm.c new file mode 100644 index 0000000..0625d8a --- /dev/null +++ b/src/iwm.c @@ -0,0 +1,2329 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_iwm_c[] = "@(#)$KmKId: iwm.c,v 1.111 2003-11-03 22:14:10-05 kentd Exp $"; + +#include "defc.h" + +extern int Verbose; +extern int g_vbl_count; +extern int speed_fast; +extern word32 g_slot_motor_detect; + +const byte phys_to_dos_sec[] = { + 0x00, 0x07, 0x0e, 0x06, 0x0d, 0x05, 0x0c, 0x04, + 0x0b, 0x03, 0x0a, 0x02, 0x09, 0x01, 0x08, 0x0f +}; + +const byte phys_to_prodos_sec[] = { + 0x00, 0x08, 0x01, 0x09, 0x02, 0x0a, 0x03, 0x0b, + 0x04, 0x0c, 0x05, 0x0d, 0x06, 0x0e, 0x07, 0x0f +}; + + +const byte to_disk_byte[] = { + 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, + 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, +/* 0x10 */ + 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, +/* 0x20 */ + 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, +/* 0x30 */ + 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +int g_track_bytes_35[] = { + 0x200*12, + 0x200*11, + 0x200*10, + 0x200*9, + 0x200*8 +}; + +int g_track_nibs_35[] = { + 816*12, + 816*11, + 816*10, + 816*9, + 816*8 +}; + + + +int g_fast_disk_emul = 1; +int g_slow_525_emul_wr = 0; +double g_dcycs_end_emul_wr = 0.0; +int g_fast_disk_unnib = 0; +int g_iwm_fake_fast = 0; + + +int from_disk_byte[256]; +int from_disk_byte_valid = 0; + +Iwm iwm; + +int g_apple35_sel = 0; +int head_35 = 0; +int g_iwm_motor_on = 0; + +int g_check_nibblization = 0; + +/* prototypes for IWM special routs */ +int iwm_read_data_35(Disk *dsk, int fast_disk_emul, double dcycs); +int iwm_read_data_525(Disk *dsk, int fast_disk_emul, double dcycs); +void iwm_write_data_35(Disk *dsk, word32 val, int fast_disk_emul, double dcycs); +void iwm_write_data_525(Disk *dsk, word32 val, int fast_disk_emul,double dcycs); + +void +iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525) +{ + int num_tracks; + int i; + + num_tracks = MAX_TRACKS; + + dsk->dcycs_last_read = 0.0; + dsk->name_ptr = 0; + dsk->partition_name = 0; + dsk->partition_num = -1; + dsk->fd = -1; + dsk->force_size = 0; + dsk->image_start = 0; + dsk->image_size = 0; + dsk->smartport = smartport; + dsk->disk_525 = disk_525; + dsk->drive = drive; + dsk->cur_qtr_track = 0; + dsk->image_type = 0; + dsk->vol_num = 254; + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + dsk->disk_dirty = 0; + dsk->just_ejected = 0; + dsk->last_phase = 0; + dsk->nib_pos = 0; + dsk->num_tracks = 0; + + for(i = 0; i < num_tracks; i++) { + dsk->tracks[i].dsk = dsk; + dsk->tracks[i].nib_area = 0; + dsk->tracks[i].track_dirty = 0; + dsk->tracks[i].overflow_size = 0; + dsk->tracks[i].track_len = 0; + dsk->tracks[i].unix_pos = -1; + dsk->tracks[i].unix_len = -1; + } +} + +void +iwm_init() +{ + int val; + int i; + + for(i = 0; i < 2; i++) { + iwm_init_drive(&(iwm.drive525[i]), 0, i, 1); + iwm_init_drive(&(iwm.drive35[i]), 0, i, 0); + } + + for(i = 0; i < MAX_C7_DISKS; i++) { + iwm_init_drive(&(iwm.smartport[i]), 1, i, 0); + } + + if(from_disk_byte_valid == 0) { + for(i = 0; i < 256; i++) { + from_disk_byte[i] = -1; + } + for(i = 0; i < 64; i++) { + val = to_disk_byte[i]; + from_disk_byte[val] = i; + } + from_disk_byte_valid = 1; + } else { + halt_printf("iwm_init called twice!\n"); + } + + iwm_reset(); +} + +void +iwm_reset() +{ + iwm.q6 = 0; + iwm.q7 = 0; + iwm.motor_on = 0; + iwm.motor_on35 = 0; + iwm.motor_off = 0; + iwm.motor_off_vbl_count = 0; + iwm.step_direction35 = 0; + iwm.head35 = 0; + iwm.drive_select = 0; + iwm.iwm_mode = 0; + iwm.enable2 = 0; + iwm.reset = 0; + iwm.iwm_phase[0] = 0; + iwm.iwm_phase[1] = 0; + iwm.iwm_phase[2] = 0; + iwm.iwm_phase[3] = 0; + iwm.previous_write_val = 0; + iwm.previous_write_bits = 0; + + g_iwm_motor_on = 0; + g_apple35_sel = 0; +} + +void +draw_iwm_status(int line, char *buf) +{ + char *flag[2][2]; + + flag[0][0] = " "; + flag[0][1] = " "; + flag[1][0] = " "; + flag[1][1] = " "; + + if(g_iwm_motor_on) { + flag[g_apple35_sel][iwm.drive_select] = "*"; + } + + sprintf(buf, "s6d1:%2d%s s6d2:%2d%s s5d1:%2d/%d%s " + "s5d2:%2d/%d%s fast_disk_emul:%d,%d c036:%02x", + iwm.drive525[0].cur_qtr_track >> 2, flag[0][0], + iwm.drive525[1].cur_qtr_track >> 2, flag[0][1], + iwm.drive35[0].cur_qtr_track >> 1, + iwm.drive35[0].cur_qtr_track & 1, flag[1][0], + iwm.drive35[1].cur_qtr_track >> 1, + iwm.drive35[1].cur_qtr_track & 1, flag[1][1], + g_fast_disk_emul, g_slow_525_emul_wr, + (speed_fast << 7) + g_slot_motor_detect); + + video_update_status_line(line, buf); +} + +void +iwm_flush_disk_to_unix(Disk *dsk) +{ + byte buffer[0x4000]; + int num_dirty; + int j; + int ret; + int unix_pos; + int unix_len; + + if(dsk->disk_dirty == 0 || dsk->write_through_to_unix == 0) { + return; + } + + printf("Writing disk %s to Unix\n", dsk->name_ptr); + dsk->disk_dirty = 0; + num_dirty = 0; + + /* Dirty data! */ + for(j = 0; j < dsk->num_tracks; j++) { + + ret = disk_track_to_unix(dsk, j, &(buffer[0])); + + if(ret != 1 && ret != 0) { + printf("iwm_flush_disk_to_unix ret: %d, cannot write " + "image to unix\n", ret); + halt_printf("Adjusting image not to write through!\n"); + dsk->write_through_to_unix = 0; + break; + } + + if(ret != 1) { + /* not at an even track, or not dirty */ + continue; + } + if((j & 3) != 0 && dsk->disk_525) { + halt_printf("Valid data on a non-whole trk: %03x\n", j); + continue; + } + + num_dirty++; + + /* Write it out */ + unix_pos = dsk->tracks[j].unix_pos; + unix_len = dsk->tracks[j].unix_len; + if(unix_pos < 0 || unix_len < 0x1000) { + halt_printf("Disk:%s trk:%d, unix_pos:%08x, len:%08x\n", + dsk->name_ptr, j, unix_pos, unix_len); + break; + } + + ret = lseek(dsk->fd, unix_pos, SEEK_SET); + if(ret != unix_pos) { + halt_printf("lseek 525: %08x, errno: %d\n", ret, errno); + } + + ret = write(dsk->fd, &(buffer[0]), unix_len); + if(ret != unix_len) { + printf("write: %08x, errno:%d, qtrk: %02x, disk: %s\n", + ret, errno, j, dsk->name_ptr); + } + } + + if(num_dirty == 0) { + halt_printf("Drive %s was dirty, but no track was dirty!\n", + dsk->name_ptr); + } + +} + +/* Check for dirty disk 3 times a second */ + +void +iwm_vbl_update(int doit_3_persec) +{ + Disk *dsk; + int motor_on; + int i; + + if(iwm.motor_on && iwm.motor_off) { + if(iwm.motor_off_vbl_count <= g_vbl_count) { + printf("Disk timer expired, drive off: %08x\n", + g_vbl_count); + iwm.motor_on = 0; + iwm.motor_off = 0; + } + } + + if(!doit_3_persec) { + return; + } + + motor_on = iwm.motor_on; + if(g_apple35_sel) { + motor_on = iwm.motor_on35; + } + + if(motor_on == 0 || iwm.motor_off) { + /* Disk not spinning, see if any dirty tracks to flush */ + /* out to Unix */ + for(i = 0; i < 2; i++) { + dsk = &(iwm.drive525[i]); + iwm_flush_disk_to_unix(dsk); + } + for(i = 0; i < 2; i++) { + dsk = &(iwm.drive35[i]); + iwm_flush_disk_to_unix(dsk); + } + } +} + + +void +iwm_show_stats() +{ + printf("IWM stats: q7,q6: %d, %d, reset,enable2: %d,%d, mode: %02x\n", + iwm.q7, iwm.q6, iwm.reset, iwm.enable2, iwm.iwm_mode); + printf("motor: %d,%d, motor35:%d drive: %d, on: %d, head35: %d " + "phs: %d %d %d %d\n", + iwm.motor_on, iwm.motor_off, g_iwm_motor_on, + iwm.drive_select, g_apple35_sel, + head_35, iwm.iwm_phase[0], iwm.iwm_phase[1], iwm.iwm_phase[2], + iwm.iwm_phase[3]); + printf("iwm.drive525[0].fd: %d, [1].fd: %d\n", + iwm.drive525[0].fd, iwm.drive525[1].fd); + printf("iwm.drive525[0].last_phase: %d, [1].last_phase: %d\n", + iwm.drive525[0].last_phase, iwm.drive525[1].last_phase); +} + +void +iwm_touch_switches(int loc, double dcycs) +{ + Disk *dsk; + int phase; + int on; + int drive; + + if(iwm.reset) { + iwm_printf("IWM under reset: %d, enable2: %d\n", iwm.reset, + iwm.enable2); + } + + on = loc & 1; + drive = iwm.drive_select; + phase = loc >> 1; + if(g_apple35_sel) { + dsk = &(iwm.drive35[drive]); + } else { + dsk = &(iwm.drive525[drive]); + } + + + if(loc < 8) { + /* phase adjustments. See if motor is on */ + + iwm.iwm_phase[phase] = on; + + if(iwm.motor_on) { + if(g_apple35_sel) { + if(phase == 3 && on) { + iwm_do_action35(dcycs); + } + } else if(on) { + /* Move apple525 head */ + iwm525_phase_change(drive, phase); + } + } + /* See if enable or reset is asserted */ + if(iwm.iwm_phase[0] && iwm.iwm_phase[2]) { + iwm.reset = 1; + iwm_printf("IWM reset active\n"); + } else { + iwm.reset = 0; + } + if(iwm.iwm_phase[1] && iwm.iwm_phase[3]) { + iwm.enable2 = 1; + iwm_printf("IWM ENABLE2 active\n"); + } else { + iwm.enable2 = 0; + } + } else { + /* loc >= 8 */ + switch(loc) { + case 0x8: + iwm_printf("Turning IWM motor off!\n"); + if(iwm.iwm_mode & 0x04) { + /* Turn off immediately */ + iwm.motor_off = 0; + iwm.motor_on = 0; + } else { + /* 1 second delay */ + if(iwm.motor_on && !iwm.motor_off) { + iwm.motor_off = 1; + iwm.motor_off_vbl_count = g_vbl_count + + 60; + } + } + + if(g_iwm_motor_on || g_slow_525_emul_wr) { + /* recalc current speed */ + set_halt(HALT_EVENT); + } + + g_iwm_motor_on = 0; + g_slow_525_emul_wr = 0; + break; + case 0x9: + iwm_printf("Turning IWM motor on!\n"); + iwm.motor_on = 1; + iwm.motor_off = 0; + + if(g_iwm_motor_on == 0) { + /* recalc current speed */ + set_halt(HALT_EVENT); + } + g_iwm_motor_on = 1; + + break; + case 0xa: + case 0xb: + iwm.drive_select = on; + break; + case 0xc: + case 0xd: + iwm.q6 = on; + break; + case 0xe: + case 0xf: + iwm.q7 = on; + break; + default: + printf("iwm_touch_switches: loc: %02x unknown!\n", loc); + exit(2); + } + } + + if(!iwm.q7) { + iwm.previous_write_bits = 0; + } + + if((dcycs > g_dcycs_end_emul_wr) && g_slow_525_emul_wr) { + set_halt(HALT_EVENT); + g_slow_525_emul_wr = 0; + } +} + +void +iwm_move_to_track(Disk *dsk, int new_track) +{ + int disk_525; + int dr; + + disk_525 = dsk->disk_525; + + if(new_track < 0) { + new_track = 0; + } + if(new_track >= dsk->num_tracks) { + if(disk_525) { + new_track = dsk->num_tracks - 4; + } else { + new_track = dsk->num_tracks - 2 + iwm.head35; + } + + if(new_track <= 0) { + new_track = 0; + } + } + + if(dsk->cur_qtr_track != new_track) { + dr = dsk->drive + 1; + if(disk_525) { + iwm_printf("s6d%d Track: %d.%02d\n", dr, + new_track >> 2, 25* (new_track & 3)); + } else { + iwm_printf("s5d%d Track: %d Side: %d\n", dr, + new_track >> 1, new_track & 1); + } + + dsk->cur_qtr_track = new_track; + } +} + +void +iwm525_phase_change(int drive, int phase) +{ + Disk *dsk; + int qtr_track; + int last_phase; + int phase_up; + int phase_down; + int delta; + + phase_up = (phase - 1) & 3; + phase_down = (phase + 1) & 3; + + dsk = &(iwm.drive525[drive]); + last_phase = dsk->last_phase; + + qtr_track = dsk->cur_qtr_track; + + delta = 0; + if(last_phase == phase_up) { + delta = 2; + last_phase = phase; + } else if(last_phase == phase_down) { + delta = -2; + last_phase = phase; + } + + qtr_track += delta; + if(qtr_track < 0) { + printf("GRIND...GRIND...GRIND\n"); + qtr_track = 0; + last_phase = 0; + } + if(qtr_track > 4*34) { + printf("Disk arm moved past track 0x21, moving it back\n"); + qtr_track = 4*34; + last_phase = 0; + } + + iwm_move_to_track(dsk, qtr_track); + + dsk->last_phase = last_phase; + + iwm_printf("Moving drive to qtr track: %04x, %d, %d, %d, " + "%d %d %d %d\n", + qtr_track, phase, delta, last_phase, iwm.iwm_phase[0], + iwm.iwm_phase[1], iwm.iwm_phase[2], iwm.iwm_phase[3]); + + /* sanity check stepping algorithm */ + if((qtr_track & 7) == 0) { + /* check for just access phase 0 */ + if(last_phase != 0 ) { + halt_printf("last_phase: %d!\n", last_phase); + } + } +} + +int +iwm_read_status35(double dcycs) +{ + Disk *dsk; + int drive; + int state; + int tmp; + + drive = iwm.drive_select; + dsk = &(iwm.drive35[drive]); + + if(iwm.motor_on) { + /* Read status */ + state = (iwm.iwm_phase[1] << 3) + (iwm.iwm_phase[0] << 2) + + (head_35 << 1) + iwm.iwm_phase[2]; + + iwm_printf("Iwm status read state: %02x\n", state); + + switch(state) { + case 0x00: /* step direction */ + return iwm.step_direction35; + break; + case 0x01: /* lower head activate */ + /* also return instantaneous data from head */ + iwm.head35 = 0; + iwm_move_to_track(dsk, (dsk->cur_qtr_track & (-2))); + return (((int)dcycs) & 1); + break; + case 0x02: /* disk in place */ + /* 1 = no disk, 0 = disk */ + iwm_printf("read disk in place, num_tracks: %d\n", + dsk->num_tracks); + tmp = (dsk->num_tracks <= 0); + return tmp; + break; + case 0x03: /* upper head activate */ + /* also return instantaneous data from head */ + iwm.head35 = 1; + iwm_move_to_track(dsk, (dsk->cur_qtr_track | 1)); + return (((int)dcycs) & 1); + break; + case 0x04: /* disk is stepping? */ + /* 1 = not stepping, 0 = stepping */ + return 1; + break; + case 0x05: /* Unknown function of ROM 03? */ + /* 1 = or $20 into 0xe1/f24+drive, 0 = don't */ + return 1; + break; + case 0x06: /* disk is locked */ + /* 0 = locked, 1 = unlocked */ + return (!dsk->write_prot); + break; + case 0x08: /* motor on */ + /* 0 = on, 1 = off */ + return !iwm.motor_on35; + break; + case 0x09: /* number of sides */ + /* 1 = 2 sides, 0 = 1 side */ + return 1; + break; + case 0x0a: /* at track 0 */ + /* 1 = not at track 0, 0 = there */ + tmp = (dsk->cur_qtr_track != 0); + iwm_printf("Read at track0_35: %d\n", tmp); + return tmp; + break; + case 0x0b: /* disk ready??? */ + /* 0 = ready, 1 = not ready? */ + tmp = !iwm.motor_on35; + iwm_printf("Read disk ready, ret: %d\n", tmp); + return tmp; + break; + case 0x0c: /* disk switched?? */ + /* 0 = not switched, 1 = switched? */ + tmp = (dsk->just_ejected != 0); + iwm_printf("Read disk switched: %d\n", tmp); + return tmp; + break; + case 0x0d: /* false read when ejecting disk */ + return 1; + case 0x0e: /* tachometer */ + halt_printf("Reading tachometer!\n"); + return (((int)dcycs) & 1); + break; + case 0x0f: /* drive installed? */ + /* 0 = drive exists, 1 = no drive */ + if(drive) { + /* pretend no drive 1 */ + return 1; + } + return 0; + break; + default: + halt_printf("Read 3.5 status, state: %02x\n", state); + return 1; + } + } else { + iwm_printf("Read 3.5 status with drive off!\n"); + return 1; + } +} + +void +iwm_do_action35(double dcycs) +{ + Disk *dsk; + int drive; + int state; + + drive = iwm.drive_select; + dsk = &(iwm.drive35[drive]); + + if(iwm.motor_on) { + /* Perform action */ + state = (iwm.iwm_phase[1] << 3) + (iwm.iwm_phase[0] << 2) + + (head_35 << 1) + iwm.iwm_phase[2]; + switch(state) { + case 0x00: /* Set step direction inward */ + /* towards higher tracks */ + iwm.step_direction35 = 0; + iwm_printf("Iwm set step dir35 = 0\n"); + break; + case 0x01: /* Set step direction outward */ + /* towards lower tracks */ + iwm.step_direction35 = 1; + iwm_printf("Iwm set step dir35 = 1\n"); + break; + case 0x03: /* reset disk-switched flag? */ + iwm_printf("Iwm reset disk switch\n"); + dsk->just_ejected = 0; + /* set_halt(1); */ + break; + case 0x04: /* step disk */ + if(iwm.step_direction35) { + iwm_move_to_track(dsk, dsk->cur_qtr_track - 2); + } else { + iwm_move_to_track(dsk, dsk->cur_qtr_track + 2); + } + break; + case 0x08: /* turn motor on */ + iwm_printf("Iwm set motor_on35 = 1\n"); + iwm.motor_on35 = 1; + break; + case 0x09: /* turn motor off */ + iwm_printf("Iwm set motor_on35 = 0\n"); + iwm.motor_on35 = 0; + break; + case 0x0d: /* eject disk */ + eject_disk(dsk); + break; + case 0x02: + case 0x07: + case 0x0b: /* hacks to allow AE 1.6MB driver to not crash me */ + break; + default: + halt_printf("Do 3.5 action, state: %02x\n", state); + return; + } + } else { + halt_printf("Set 3.5 status with drive off!\n"); + return; + } +} + +void +iwm_set_apple35_sel(int newval) +{ + if(g_apple35_sel != newval) { + /* Handle speed changes */ + set_halt(HALT_EVENT); + } + + g_apple35_sel = newval; +} + +int +iwm_read_c0ec(double dcycs) +{ + Disk *dsk; + int drive; + + iwm.q6 = 0; + + if(iwm.q7 == 0 && iwm.enable2 == 0 && iwm.motor_on) { + drive = iwm.drive_select; + if(g_apple35_sel) { + dsk = &(iwm.drive35[drive]); + return iwm_read_data_35(dsk, g_fast_disk_emul, dcycs); + } else { + dsk = &(iwm.drive525[drive]); + return iwm_read_data_525(dsk, g_fast_disk_emul, dcycs); + } + + } + + return read_iwm(0xc, dcycs); +} + + +int +read_iwm(int loc, double dcycs) +{ + Disk *dsk; + word32 status; + double diff_dcycs; + double dcmp; + int on; + int state; + int drive; + int val; + + loc = loc & 0xf; + on = loc & 1; + + if(loc == 0xc) { + iwm.q6 = 0; + } else { + iwm_touch_switches(loc, dcycs); + } + + state = (iwm.q7 << 1) + iwm.q6; + drive = iwm.drive_select; + if(g_apple35_sel) { + dsk = &(iwm.drive35[drive]); + } else { + dsk = &(iwm.drive525[drive]); + } + + if(on) { + /* odd address, return 0 */ + return 0; + } else { + /* even address */ + switch(state) { + case 0x00: /* q7 = 0, q6 = 0 */ + if(iwm.enable2) { + return iwm_read_enable2(dcycs); + } else { + if(iwm.motor_on) { + return iwm_read_data(dsk, + g_fast_disk_emul, dcycs); + } else { + iwm_printf("read iwm st 0, m off!\n"); +/* HACK!!!! */ + return 0xff; + //return (((int)dcycs) & 0x7f) + 0x80; + } + } + break; + case 0x01: /* q7 = 0, q6 = 1 */ + /* read IWM status reg */ + if(iwm.enable2) { + iwm_printf("Read status under enable2: 1\n"); + status = 1; + } else { + if(g_apple35_sel) { + status = iwm_read_status35(dcycs); + } else { + status = dsk->write_prot; + } + } + + val = (status << 7) + (iwm.motor_on << 5) + + iwm.iwm_mode; + iwm_printf("Read status: %02x\n", val); + + return val; + break; + case 0x02: /* q7 = 1, q6 = 0 */ + /* read handshake register */ + if(iwm.enable2) { + return iwm_read_enable2_handshake(dcycs); + } else { + status = 0xc0; + diff_dcycs = dcycs - dsk->dcycs_last_read; + dcmp = 16.0; + if(dsk->disk_525 == 0) { + dcmp = 32.0; + } + if(diff_dcycs > dcmp) { + iwm_printf("Write underrun!\n"); + iwm_printf("cur: %f, dc_last: %f\n", + dcycs, dsk->dcycs_last_read); + status = status & 0xbf; + } + return status; + } + break; + case 0x03: /* q7 = 1, q6 = 1 */ + halt_printf("read iwm state 3!\n"); + return 0; + break; + } + + } + halt_printf("Got to end of read_iwm, loc: %02x!\n", loc); + + return 0; +} + +void +write_iwm(int loc, int val, double dcycs) +{ + Disk *dsk; + int on; + int state; + int drive; + int fast_writes; + + loc = loc & 0xf; + on = loc & 1; + + iwm_touch_switches(loc, dcycs); + + state = (iwm.q7 << 1) + iwm.q6; + drive = iwm.drive_select; + fast_writes = g_fast_disk_emul; + if(g_apple35_sel) { + dsk = &(iwm.drive35[drive]); + } else { + dsk = &(iwm.drive525[drive]); + fast_writes = !g_slow_525_emul_wr && fast_writes; + } + + if(on) { + /* odd address, write something */ + if(state == 0x03) { + /* q7, q6 = 1,1 */ + if(iwm.motor_on) { + if(iwm.enable2) { + iwm_write_enable2(val, dcycs); + } else { + iwm_write_data(dsk, val, + fast_writes, dcycs); + } + } else { + /* write mode register */ + val = val & 0x1f; + iwm.iwm_mode = val; + if(val != 0 && val != 0x0f && val != 0x07 && + val != 0x04 && val != 0x0b) { + halt_printf("set iwm_mode:%02x!\n",val); + } + } + } else { + if(iwm.enable2) { + iwm_write_enable2(val, dcycs); + } else { + printf("Write iwm1, st: %02x, loc: %x: %02x\n", + state, loc, val); + } + } + return; + } else { + /* even address */ + if(iwm.enable2) { + iwm_write_enable2(val, dcycs); + } else { + iwm_printf("Write iwm2, st: %02x, loc: %x: %02x\n", + state, loc, val); + } + return; + } + + halt_printf("Got to end of write_iwm, loc:%02x, val: %02x\n", loc, val); + + return; + +} + + + +int +iwm_read_enable2(double dcycs) +{ + iwm_printf("Read under enable2!\n"); + return 0xff; +} + +int g_cnt_enable2_handshake = 0; + +int +iwm_read_enable2_handshake(double dcycs) +{ + int val; + + iwm_printf("Read handshake under enable2!\n"); + + val = 0xc0; + g_cnt_enable2_handshake++; + if(g_cnt_enable2_handshake > 3) { + g_cnt_enable2_handshake = 0; + val = 0x80; + } + + return val; +} + +void +iwm_write_enable2(int val, double dcycs) +{ + iwm_printf("Write under enable2: %02x!\n", val); + + return; +} + +int +iwm_read_data(Disk *dsk, int fast_disk_emul, double dcycs) +{ + if(dsk->disk_525) { + return iwm_read_data_525(dsk, fast_disk_emul, dcycs); + } else { + return iwm_read_data_35(dsk, fast_disk_emul, dcycs); + } +} + +void +iwm_write_data(Disk *dsk, word32 val, int fast_disk_emul, double dcycs) +{ + if(dsk->disk_525) { + iwm_write_data_525(dsk, val, fast_disk_emul, dcycs); + } else { + iwm_write_data_35(dsk, val, fast_disk_emul, dcycs); + } +} + +#undef IWM_READ_ROUT +#undef IWM_WRITE_ROUT +#undef IWM_CYC_MULT +#undef IWM_DISK_525 + +#define IWM_READ_ROUT iwm_read_data_35 +#define IWM_WRITE_ROUT iwm_write_data_35 +#define IWM_CYC_MULT 1 +#define IWM_DISK_525 0 + +#define INCLUDE_IWM_RCSID_C +#include "iwm_35_525.h" +#undef INCLUDE_IWM_RCSID_C + +#undef IWM_READ_ROUT +#undef IWM_WRITE_ROUT +#undef IWM_CYC_MULT +#undef IWM_DISK_525 + +#define IWM_READ_ROUT iwm_read_data_525 +#define IWM_WRITE_ROUT iwm_write_data_525 +#define IWM_CYC_MULT 2 +#define IWM_DISK_525 1 +#include "iwm_35_525.h" + +#undef IWM_READ_ROUT +#undef IWM_WRITE_ROUT +#undef IWM_CYC_MULT +#undef IWM_DISK_525 + + + + + +/* c600 */ +void +sector_to_partial_nib(byte *in, byte *nib_ptr) +{ + byte *aux_buf; + byte *nib_out; + int val; + int val2; + int x; + int i; + + /* Convert 256(+1) data bytes to 342+1 disk nibbles */ + + aux_buf = nib_ptr; + nib_out = nib_ptr + 0x56; + + for(i = 0; i < 0x56; i++) { + aux_buf[i] = 0; + } + + x = 0x55; + for(i = 0x101; i >= 0; i--) { + val = in[i]; + if(i >= 0x100) { + val = 0; + } + val2 = (aux_buf[x] << 1) + (val & 1); + val = val >> 1; + val2 = (val2 << 1) + (val & 1); + val = val >> 1; + nib_out[i] = val; + aux_buf[x] = val2; + x--; + if(x < 0) { + x = 0x55; + } + } +} + + +int +disk_unnib_4x4(Disk *dsk) +{ + int val1; + int val2; + + val1 = iwm_read_data(dsk, 1, 0); + val2 = iwm_read_data(dsk, 1, 0); + + return ((val1 << 1) + 1) & val2; +} + +int +iwm_denib_track525(Disk *dsk, Track *trk, int qtr_track, byte *outbuf) +{ + byte aux_buf[0x80]; + byte *buf; + int sector_done[16]; + int num_sectors_done; + int track_len; + int vol, track, phys_sec, log_sec, cksum; + int val; + int val2; + int prev_val; + int x; + int my_nib_cnt; + int save_qtr_track; + int save_nib_pos; + int tmp_nib_pos; + int status; + int i; + + save_qtr_track = dsk->cur_qtr_track; + save_nib_pos = dsk->nib_pos; + + iwm_move_to_track(dsk, qtr_track); + + dsk->nib_pos = 0; + g_fast_disk_unnib = 1; + + track_len = trk->track_len; + + for(i = 0; i < 16; i++) { + sector_done[i] = 0; + } + + num_sectors_done = 0; + + val = 0; + status = -1; + my_nib_cnt = 0; + while(my_nib_cnt++ < 2*track_len) { + /* look for start of a sector */ + if(val != 0xd5) { + val = iwm_read_data(dsk, 1, 0); + continue; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xaa) { + continue; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0x96) { + continue; + } + + /* It's a sector start */ + vol = disk_unnib_4x4(dsk); + track = disk_unnib_4x4(dsk); + phys_sec = disk_unnib_4x4(dsk); + if(phys_sec < 0 || phys_sec > 15) { + printf("Track %02x, read sec as %02x\n", qtr_track>>2, + phys_sec); + break; + } + if(dsk->image_type == DSK_TYPE_DOS33) { + log_sec = phys_to_dos_sec[phys_sec]; + } else { + log_sec = phys_to_prodos_sec[phys_sec]; + } + cksum = disk_unnib_4x4(dsk); + if((vol ^ track ^ phys_sec ^ cksum) != 0) { + /* not correct format */ + printf("Track %02x not DOS 3.3 since hdr cksum, %02x " + "%02x %02x %02x\n", + qtr_track>>2, vol, track, phys_sec, cksum); + break; + } + + /* see what sector it is */ + if(track != (qtr_track>>2) || (phys_sec < 0)||(phys_sec > 15)) { + printf("Track %02x bad since track: %02x, sec: %02x\n", + qtr_track>>2, track, phys_sec); + break; + } + + if(sector_done[phys_sec]) { + printf("Already done sector %02x on track %02x!\n", + phys_sec, qtr_track>>2); + break; + } + + /* So far so good, let's do it! */ + val = 0; + i = 0; + while(i < NIBS_FROM_ADDR_TO_DATA) { + i++; + if(val != 0xd5) { + val = iwm_read_data(dsk, 1, 0); + continue; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xaa) { + continue; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xad) { + continue; + } + + /* got it, just break */ + break; + } + + if(i >= NIBS_FROM_ADDR_TO_DATA) { + printf("No data header, track %02x, sec %02x\n", + qtr_track>>2, phys_sec); + printf("nib_pos: %08x\n", dsk->nib_pos); + break; + } + + buf = outbuf + 0x100*log_sec; + + /* Data start! */ + prev_val = 0; + for(i = 0x55; i >= 0; i--) { + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + if(val2 < 0) { + printf("Bad data area1, val:%02x,val2:%02x\n", + val, val2); + printf(" i:%03x,n_pos:%04x\n", i, dsk->nib_pos); + break; + } + prev_val = val2 ^ prev_val; + aux_buf[i] = prev_val; + } + + /* rest of data area */ + for(i = 0; i < 0x100; i++) { + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + if(val2 < 0) { + printf("Bad data area2, read: %02x\n", val); + printf(" nib_pos: %04x\n", dsk->nib_pos); + break; + } + prev_val = val2 ^ prev_val; + buf[i] = prev_val; + } + + /* checksum */ + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + if(val2 < 0) { + printf("Bad data area3, read: %02x\n", val); + printf(" nib_pos: %04x\n", dsk->nib_pos); + break; + } + if(val2 != prev_val) { + printf("Bad data cksum, got %02x, wanted: %02x\n", + val2, prev_val); + printf(" nib_pos: %04x\n", dsk->nib_pos); + break; + } + + /* Got this far, data is good, merge aux_buf into buf */ + x = 0x55; + for(i = 0; i < 0x100; i++) { + val = aux_buf[x]; + val2 = (buf[i] << 1) + (val & 1); + val = val >> 1; + val2 = (val2 << 1) + (val & 1); + buf[i] = val2; + val = val >> 1; + aux_buf[x] = val; + x--; + if(x < 0) { + x = 0x55; + } + } + sector_done[phys_sec] = 1; + num_sectors_done++; + if(num_sectors_done >= 16) { + status = 0; + break; + } + } + + tmp_nib_pos = dsk->nib_pos; + iwm_move_to_track(dsk, save_qtr_track); + dsk->nib_pos = save_nib_pos; + g_fast_disk_unnib = 0; + + if(status == 0) { + return 1; + } + + printf("Nibblization not done, %02x sectors found on track %02x\n", + num_sectors_done, qtr_track>>2); + printf("my_nib_cnt: %04x, nib_pos: %04x, trk_len: %04x\n", my_nib_cnt, + tmp_nib_pos, track_len); + for(i = 0; i < 16; i++) { + printf("sector_done[%d] = %d\n", i, sector_done[i]); + } + return -1; +} + +int +iwm_denib_track35(Disk *dsk, Track *trk, int qtr_track, byte *outbuf) +{ + word32 buf_c00[0x100]; + word32 buf_d00[0x100]; + word32 buf_e00[0x100]; + byte *buf; + word32 tmp_5c, tmp_5d, tmp_5e; + word32 tmp_66, tmp_67; + int sector_done[16]; + int num_sectors_done; + int track_len; + int phys_track, phys_sec, phys_side, phys_capacity, cksum; + int tmp; + int track, side; + int num_sectors; + int val; + int val2; + int x, y; + int carry; + int my_nib_cnt; + int save_qtr_track; + int save_nib_pos; + int status; + int i; + + save_qtr_track = dsk->cur_qtr_track; + save_nib_pos = dsk->nib_pos; + + iwm_move_to_track(dsk, qtr_track); + + dsk->nib_pos = 0; + g_fast_disk_unnib = 1; + + track_len = trk->track_len; + + num_sectors = g_track_bytes_35[qtr_track >> 5] >> 9; + + for(i = 0; i < num_sectors; i++) { + sector_done[i] = 0; + } + + num_sectors_done = 0; + + val = 0; + status = -1; + my_nib_cnt = 0; + + track = qtr_track >> 1; + side = qtr_track & 1; + + while(my_nib_cnt++ < 2*track_len) { + /* look for start of a sector */ + if(val != 0xd5) { + val = iwm_read_data(dsk, 1, 0); + continue; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xaa) { + continue; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0x96) { + continue; + } + + /* It's a sector start */ + val = iwm_read_data(dsk, 1, 0); + phys_track = from_disk_byte[val]; + if(phys_track != (track & 0x3f)) { + printf("Track %02x.%d, read track %02x, %02x\n", + track, side, phys_track, val); + break; + } + + phys_sec = from_disk_byte[iwm_read_data(dsk, 1, 0)]; + if(phys_sec < 0 || phys_sec >= num_sectors) { + printf("Track %02x.%d, read sector %02x??\n", + track, side, phys_sec); + break; + } + phys_side = from_disk_byte[iwm_read_data(dsk, 1, 0)]; + + if(phys_side != ((side << 5) + (track >> 6))) { + printf("Track %02x.%d, read side %02x??\n", + track, side, phys_side); + break; + } + phys_capacity = from_disk_byte[iwm_read_data(dsk, 1, 0)]; + if(phys_capacity != 0x24 && phys_capacity != 0x22) { + printf("Track %02x.%x capacity: %02x != 0x24/22\n", + track, side, phys_capacity); + } + cksum = from_disk_byte[iwm_read_data(dsk, 1, 0)]; + + tmp = phys_track ^ phys_sec ^ phys_side ^ phys_capacity; + if(cksum != tmp) { + printf("Track %02x.%d, sector %02x, cksum: %02x.%02x\n", + track, side, phys_sec, cksum, tmp); + break; + } + + + if(sector_done[phys_sec]) { + printf("Already done sector %02x on track %02x.%x!\n", + phys_sec, track, side); + break; + } + + /* So far so good, let's do it! */ + val = 0; + for(i = 0; i < 38; i++) { + val = iwm_read_data(dsk, 1, 0); + if(val == 0xd5) { + break; + } + } + if(val != 0xd5) { + printf("No data header, track %02x.%x, sec %02x\n", + track, side, phys_sec); + break; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xaa) { + printf("Bad data hdr1,val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + printf("nib_pos: %08x\n", dsk->nib_pos); + break; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xad) { + printf("Bad data hdr2,val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + break; + } + + buf = outbuf + (phys_sec << 9); + + /* check sector again */ + val = from_disk_byte[iwm_read_data(dsk, 1, 0)]; + if(val != phys_sec) { + printf("Bad data hdr3,val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + break; + } + + /* Data start! */ + tmp_5c = 0; + tmp_5d = 0; + tmp_5e = 0; + y = 0xaf; + carry = 0; + + while(y > 0) { +/* 626f */ + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + if(val2 < 0) { + printf("Bad data area1b, read: %02x\n", val); + printf(" i:%03x,n_pos:%04x\n", i, dsk->nib_pos); + break; + } + tmp_66 = val2; + + tmp_5c = tmp_5c << 1; + carry = (tmp_5c >> 8); + tmp_5c = (tmp_5c + carry) & 0xff; + + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + if(val2 < 0) { + printf("Bad data area2, read: %02x\n", val); + break; + } + + val2 = val2 + ((tmp_66 << 2) & 0xc0); + + val2 = val2 ^ tmp_5c; + buf_c00[y] = val2; + + tmp_5e = val2 + tmp_5e + carry; + carry = (tmp_5e >> 8); + tmp_5e = tmp_5e & 0xff; +/* 62b8 */ + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + val2 = val2 + ((tmp_66 << 4) & 0xc0); + val2 = val2 ^ tmp_5e; + buf_d00[y] = val2; + tmp_5d = val2 + tmp_5d + carry; + + carry = (tmp_5d >> 8); + tmp_5d = tmp_5d & 0xff; + + y--; + if(y <= 0) { + break; + } + +/* 6274 */ + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + val2 = val2 + ((tmp_66 << 6) & 0xc0); + val2 = val2 ^ tmp_5d; + buf_e00[y+1] = val2; + + tmp_5c = val2 + tmp_5c + carry; + carry = (tmp_5c >> 8); + tmp_5c = tmp_5c & 0xff; + } + +/* 62d0 */ + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val]; + + tmp_66 = (val2 << 6) & 0xc0; + tmp_67 = (val2 << 4) & 0xc0; + val2 = (val2 << 2) & 0xc0; + + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val] + val2; + if(tmp_5e != (word32)val2) { + printf("Checksum 5e bad: %02x vs %02x\n", tmp_5e, val2); + printf("val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + break; + } + + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val] + tmp_67; + if(tmp_5d != (word32)val2) { + printf("Checksum 5d bad: %02x vs %02x\n", tmp_5e, val2); + printf("val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + break; + } + + val = iwm_read_data(dsk, 1, 0); + val2 = from_disk_byte[val] + tmp_66; + if(tmp_5c != (word32)val2) { + printf("Checksum 5c bad: %02x vs %02x\n", tmp_5e, val2); + printf("val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + break; + } + + /* Whew, got it!...check for DE AA */ + val = iwm_read_data(dsk, 1, 0); + if(val != 0xde) { + printf("Bad data epi1,val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + printf("nib_pos: %08x\n", dsk->nib_pos); + break; + } + + val = iwm_read_data(dsk, 1, 0); + if(val != 0xaa) { + printf("Bad data epi2,val:%02x trk %02x.%x, sec %02x\n", + val, track, side, phys_sec); + break; + } + + /* Now, convert buf_c/d/e to output */ +/* 6459 */ + y = 0; + for(x = 0xab; x >= 0; x--) { + *buf++ = buf_c00[x]; + y++; + if(y >= 0x200) { + break; + } + + *buf++ = buf_d00[x]; + y++; + if(y >= 0x200) { + break; + } + + *buf++ = buf_e00[x]; + y++; + if(y >= 0x200) { + break; + } + } + + sector_done[phys_sec] = 1; + num_sectors_done++; + if(num_sectors_done >= num_sectors) { + status = 0; + break; + } + val = 0; + } + + if(status < 0) { + printf("dsk->nib_pos: %04x, status: %d\n", dsk->nib_pos, + status); + for(i = 0; i < num_sectors; i++) { + printf("sector done[%d] = %d\n", i, sector_done[i]); + } + } + + iwm_move_to_track(dsk, save_qtr_track); + dsk->nib_pos = save_nib_pos; + g_fast_disk_unnib = 0; + + if(status == 0) { + return 1; + } + + printf("Nibblization not done, %02x sectors found on track %02x\n", + num_sectors_done, qtr_track>>2); + return -1; + + + +} + +/* ret = 1 -> dirty data written out */ +/* ret = 0 -> not dirty, no error */ +/* ret < 0 -> error */ +int +disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf) +{ + Track *trk; + int disk_525; + + disk_525 = dsk->disk_525; + + trk = &(dsk->tracks[qtr_track]); + + if(trk->track_len == 0 || trk->track_dirty == 0) { +#if 0 + printf("disk_track_to_unix: dirty: %d\n", trk->track_dirty); +#endif + return 0; + } + + trk->track_dirty = 0; + + if((qtr_track & 3) && disk_525) { + halt_printf("You wrote to phase %02x! Can't wr bk to unix!\n", + qtr_track); + dsk->write_through_to_unix = 0; + return -1; + } + + if(disk_525) { + return iwm_denib_track525(dsk, trk, qtr_track, outbuf); + } else { + return iwm_denib_track35(dsk, trk, qtr_track, outbuf); + } +} + + +void +show_hex_data(byte *buf, int count) +{ + int i; + + for(i = 0; i < count; i += 16) { + printf("%04x: %02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, + buf[i+0], buf[i+1], buf[i+2], buf[i+3], + buf[i+4], buf[i+5], buf[i+6], buf[i+7], + buf[i+8], buf[i+9], buf[i+10], buf[i+11], + buf[i+12], buf[i+13], buf[i+14], buf[i+15]); + } + +} + +void +disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size) +{ + byte buffer[0x3000]; + Track *trk; + int ret, ret2; + int i; + + if(size > 0x3000) { + printf("size %08x is > 0x3000, disk_check_nibblization\n",size); + exit(3); + } + + for(i = 0; i < size; i++) { + buffer[i] = 0; + } + + trk = &(dsk->tracks[qtr_track]); + + if(dsk->disk_525) { + ret = iwm_denib_track525(dsk, trk, qtr_track, &(buffer[0])); + } else { + ret = iwm_denib_track35(dsk, trk, qtr_track, &(buffer[0])); + } + + ret2 = -1; + for(i = 0; i < size; i++) { + if(buffer[i] != buf[i]) { + printf("buffer[%04x]: %02x != %02x\n", i, buffer[i], + buf[i]); + ret2 = i; + break; + } + } + + if(ret != 1 || ret2 >= 0) { + printf("disk_check_nib ret:%d, ret2:%d for q_track %03x\n", + ret, ret2, qtr_track); + show_hex_data(buf, 0x1000); + show_hex_data(buffer, 0x1000); + iwm_show_a_track(&(dsk->tracks[qtr_track])); + + exit(2); + } +} + + +#define TRACK_BUF_LEN 0x2000 + +void +disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, + int nib_len) +{ + byte track_buf[TRACK_BUF_LEN]; + Track *trk; + int must_clear_track; + int ret; + int len; + int i; + + /* Read track from dsk int track_buf */ + + must_clear_track = 0; + + if(unix_len > TRACK_BUF_LEN) { + printf("diks_unix_to_nib: requested len of image %s = %05x\n", + dsk->name_ptr, unix_len); + } + + if(unix_pos >= 0) { + ret = lseek(dsk->fd, unix_pos, SEEK_SET); + if(ret != unix_pos) { + printf("lseek of disk %s len 0x%x ret: %d, errno: %d\n", + dsk->name_ptr, unix_pos, ret, errno); + must_clear_track = 1; + } + + len = read(dsk->fd, track_buf, unix_len); + if(len != unix_len) { + printf("read of disk %s q_trk %d ret: %d, errno: %d\n", + dsk->name_ptr, qtr_track, ret, errno); + must_clear_track = 1; + } + } + + if(must_clear_track) { + for(i = 0; i < TRACK_BUF_LEN; i++) { + track_buf[i] = 0; + } + } + +#if 0 + printf("Q_track %02x dumped out\n", qtr_track); + + for(i = 0; i < 4096; i += 32) { + printf("%04x: %02x%02x%02x%02x%02x%02x%02x%02x " + "%02x%02x%02x%02x%02x%02x%02x%02x " + "%02x%02x%02x%02x%02x%02x%02x%02x " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", i, + track_buf[i+0], track_buf[i+1], track_buf[i+2], + track_buf[i+3], track_buf[i+4], track_buf[i+5], + track_buf[i+6], track_buf[i+7], track_buf[i+8], + track_buf[i+9], track_buf[i+10], track_buf[i+11], + track_buf[i+12], track_buf[i+13], track_buf[i+14], + track_buf[i+15], track_buf[i+16], track_buf[i+17], + track_buf[i+18], track_buf[i+19], track_buf[i+20], + track_buf[i+21], track_buf[i+22], track_buf[i+23], + track_buf[i+24], track_buf[i+25], track_buf[i+26], + track_buf[i+27], track_buf[i+28], track_buf[i+29], + track_buf[i+30], track_buf[i+31]); + } +#endif + + dsk->nib_pos = 0; /* for consistency */ + + trk = &(dsk->tracks[qtr_track]); + trk->track_dirty = 0; + trk->overflow_size = 0; + trk->track_len = 2*nib_len; + trk->unix_pos = unix_pos; + trk->unix_len = unix_len; + trk->dsk = dsk; + trk->nib_area = (byte *)malloc(trk->track_len); + + /* create nibblized image */ + + if(dsk->disk_525 && dsk->image_type == DSK_TYPE_NIB) { + iwm_nibblize_track_nib525(dsk, trk, track_buf, qtr_track); + } else if(dsk->disk_525) { + iwm_nibblize_track_525(dsk, trk, track_buf, qtr_track); + } else { + iwm_nibblize_track_35(dsk, trk, track_buf, qtr_track); + } +} + +void +iwm_nibblize_track_nib525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) +{ + byte *nib_ptr; + byte *trk_ptr; + int len; + int i; + + len = trk->track_len; + trk_ptr = track_buf; + nib_ptr = &(trk->nib_area[0]); + for(i = 0; i < len; i += 2) { + nib_ptr[i] = 8; + nib_ptr[i+1] = *trk_ptr++;; + } + + iwm_printf("Nibblized q_track %02x\n", qtr_track); +} + +void +iwm_nibblize_track_525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) +{ + byte partial_nib_buf[0x300]; + word32 *word_ptr; + word32 val; + word32 last_val; + int phys_sec; + int log_sec; + int num_sync; + int i; + + + word_ptr = (word32 *)&(trk->nib_area[0]); +#ifdef KEGS_LITTLE_ENDIAN + val = 0xff08ff08; +#else + val = 0x08ff08ff; +#endif + for(i = 0; i < trk->track_len; i += 4) { + *word_ptr++ = val; + } + + + for(phys_sec = 0; phys_sec < 16; phys_sec++) { + if(dsk->image_type == DSK_TYPE_DOS33) { + log_sec = phys_to_dos_sec[phys_sec]; + } else { + log_sec = phys_to_prodos_sec[phys_sec]; + } + + /* Create sync headers */ + if(phys_sec == 0) { + num_sync = 70; + } else { + num_sync = 14; + } + + for(i = 0; i < num_sync; i++) { + disk_nib_out(dsk, 0xff, 10); + } + disk_nib_out(dsk, 0xd5, 10); /* prolog */ + disk_nib_out(dsk, 0xaa, 8); /* prolog */ + disk_nib_out(dsk, 0x96, 8); /* prolog */ + disk_4x4_nib_out(dsk, dsk->vol_num); + disk_4x4_nib_out(dsk, qtr_track >> 2); + disk_4x4_nib_out(dsk, phys_sec); + disk_4x4_nib_out(dsk, dsk->vol_num ^ (qtr_track>>2) ^ phys_sec); + disk_nib_out(dsk, 0xde, 8); /* epi */ + disk_nib_out(dsk, 0xaa, 8); /* epi */ + disk_nib_out(dsk, 0xeb, 8); /* epi */ + + /* Inter sync */ + disk_nib_out(dsk, 0xff, 8); + for(i = 0; i < 5; i++) { + disk_nib_out(dsk, 0xff, 10); + } + disk_nib_out(dsk, 0xd5, 10); /* data prolog */ + disk_nib_out(dsk, 0xaa, 8); /* data prolog */ + disk_nib_out(dsk, 0xad, 8); /* data prolog */ + + sector_to_partial_nib( &(track_buf[log_sec*256]), + &(partial_nib_buf[0])); + + last_val = 0; + for(i = 0; i < 0x156; i++) { + val = partial_nib_buf[i]; + disk_nib_out(dsk, to_disk_byte[last_val ^ val], 8); + last_val = val; + } + disk_nib_out(dsk, to_disk_byte[last_val], 8); + + /* data epilog */ + disk_nib_out(dsk, 0xde, 8); /* epi */ + disk_nib_out(dsk, 0xaa, 8); /* epi */ + disk_nib_out(dsk, 0xeb, 8); /* epi */ + disk_nib_out(dsk, 0xff, 8); + for(i = 0; i < 6; i++) { + disk_nib_out(dsk, 0xff, 10); + } + } + + /* finish nibblization */ + disk_nib_end_track(dsk); + + iwm_printf("Nibblized q_track %02x\n", qtr_track); + + if(g_check_nibblization) { + disk_check_nibblization(dsk, qtr_track, &(track_buf[0]),0x1000); + } +} + +void +iwm_nibblize_track_35(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) +{ + int phys_to_log_sec[16]; + word32 buf_c00[0x100]; + word32 buf_d00[0x100]; + word32 buf_e00[0x100]; + byte *buf; + word32 *word_ptr; + word32 val; + int num_sectors; + int unix_len; + int log_sec; + int phys_sec; + int track; + int side; + int interleave; + int num_sync; + word32 phys_track, phys_side, capacity, cksum; + word32 tmp_5c, tmp_5d, tmp_5e, tmp_5f; + word32 tmp_63, tmp_64, tmp_65; + word32 acc_hi; + int carry; + int x, y; + int i; + + word_ptr = (word32 *)&(trk->nib_area[0]); +#ifdef KEGS_LITTLE_ENDIAN + val = 0xff08ff08; +#else + val = 0x08ff08ff; +#endif + if(trk->track_len & 3) { + halt_printf("track_len: %08x is not a multiple of 4\n", + trk->track_len); + } + + for(i = 0; i < trk->track_len; i += 4) { + *word_ptr++ = val; + } + + unix_len = trk->unix_len; + + num_sectors = (unix_len >> 9); + + for(i = 0; i < num_sectors; i++) { + phys_to_log_sec[i] = -1; + } + + phys_sec = 0; + interleave = 2; + for(log_sec = 0; log_sec < num_sectors; log_sec++) { + while(phys_to_log_sec[phys_sec] >= 0) { + phys_sec++; + if(phys_sec >= num_sectors) { + phys_sec = 0; + } + } + phys_to_log_sec[phys_sec] = log_sec; + phys_sec += interleave; + if(phys_sec >= num_sectors) { + phys_sec -= num_sectors; + } + } + + track = qtr_track >> 1; + side = qtr_track & 1; + for(phys_sec = 0; phys_sec < num_sectors; phys_sec++) { + + log_sec = phys_to_log_sec[phys_sec]; + if(log_sec < 0) { + printf("Track: %02x.%x phys_sec: %02x = %d!\n", + track, side, phys_sec, log_sec); + exit(2); + } + + /* Create sync headers */ + if(phys_sec == 0) { + num_sync = 400; + } else { + num_sync = 54; + } + + for(i = 0; i < num_sync; i++) { + disk_nib_out(dsk, 0xff, 10); + } + + disk_nib_out(dsk, 0xd5, 10); /* prolog */ + disk_nib_out(dsk, 0xaa, 8); /* prolog */ + disk_nib_out(dsk, 0x96, 8); /* prolog */ + + phys_track = track & 0x3f; + phys_side = (side << 5) + (track >> 6); + capacity = 0x22; + disk_nib_out(dsk, to_disk_byte[phys_track], 8); /* trk */ + disk_nib_out(dsk, to_disk_byte[log_sec], 8); /* sec */ + disk_nib_out(dsk, to_disk_byte[phys_side], 8); /* sides+trk */ + disk_nib_out(dsk, to_disk_byte[capacity], 8); /* capacity*/ + + cksum = (phys_track ^ log_sec ^ phys_side ^ capacity) & 0x3f; + disk_nib_out(dsk, to_disk_byte[cksum], 8); /* cksum*/ + + disk_nib_out(dsk, 0xde, 8); /* epi */ + disk_nib_out(dsk, 0xaa, 8); /* epi */ + + /* Inter sync */ + for(i = 0; i < 5; i++) { + disk_nib_out(dsk, 0xff, 10); + } + disk_nib_out(dsk, 0xd5, 10); /* data prolog */ + disk_nib_out(dsk, 0xaa, 8); /* data prolog */ + disk_nib_out(dsk, 0xad, 8); /* data prolog */ + disk_nib_out(dsk, to_disk_byte[log_sec], 8); /* sec again */ + + /* do nibblizing! */ + buf = track_buf + (log_sec << 9); + +/* 6320 */ + tmp_5e = 0; + tmp_5d = 0; + tmp_5c = 0; + y = 0; + x = 0xaf; + buf_c00[0] = 0; + buf_d00[0] = 0; + buf_e00[0] = 0; + buf_e00[1] = 0; + for(y = 0x4; y > 0; y--) { + buf_c00[x] = 0; + buf_d00[x] = 0; + buf_e00[x] = 0; + x--; + } + + while(x >= 0) { +/* 6338 */ + tmp_5c = tmp_5c << 1; + carry = (tmp_5c >> 8); + tmp_5c = (tmp_5c + carry) & 0xff; + + val = buf[y]; + tmp_5e = val + tmp_5e + carry; + carry = (tmp_5e >> 8); + tmp_5e = tmp_5e & 0xff; + + val = val ^ tmp_5c; + buf_c00[x] = val; + y++; +/* 634c */ + val = buf[y]; + tmp_5d = tmp_5d + val + carry; + carry = (tmp_5d >> 8); + tmp_5d = tmp_5d & 0xff; + val = val ^ tmp_5e; + buf_d00[x] = val; + y++; + x--; + if(x <= 0) { + break; + } + +/* 632a */ + val = buf[y]; + tmp_5c = tmp_5c + val + carry; + carry = (tmp_5c >> 8); + tmp_5c = tmp_5c & 0xff; + + val = val ^ tmp_5d; + buf_e00[x+1] = val; + y++; + } + +/* 635f */ + val = ((tmp_5c >> 2) ^ tmp_5d) & 0x3f; +/* 6367 */ + val = (val ^ tmp_5d) >> 2; +/* 636b */ + val = (val ^ tmp_5e) & 0x3f; +/* 636f */ + val = (val ^ tmp_5e) >> 2; +/* 6373 */ + tmp_5f = val; +/* 6375 */ + tmp_63 = 0; + tmp_64 = 0; + tmp_65 = 0; + acc_hi = 0; + + + y = 0xae; + while(y >= 0) { +/* 63e4 */ + /* write out acc_hi */ + val = to_disk_byte[acc_hi & 0x3f]; + disk_nib_out(dsk, val, 8); + +/* 63f2 */ + val = to_disk_byte[tmp_63 & 0x3f]; + tmp_63 = buf_c00[y]; + acc_hi = tmp_63 >> 6; + disk_nib_out(dsk, val, 8); +/* 640b */ + val = to_disk_byte[tmp_64 & 0x3f]; + tmp_64 = buf_d00[y]; + acc_hi = (acc_hi << 2) + (tmp_64 >> 6); + disk_nib_out(dsk, val, 8); + y--; + if(y < 0) { + break; + } + +/* 63cb */ + val = to_disk_byte[tmp_65 & 0x3f]; + tmp_65 = buf_e00[y+1]; + acc_hi = (acc_hi << 2) + (tmp_65 >> 6); + disk_nib_out(dsk, val, 8); + } +/* 6429 */ + val = to_disk_byte[tmp_5f & 0x3f]; + disk_nib_out(dsk, val, 8); + + val = to_disk_byte[tmp_5e & 0x3f]; + disk_nib_out(dsk, val, 8); + + val = to_disk_byte[tmp_5d & 0x3f]; + disk_nib_out(dsk, val, 8); + + val = to_disk_byte[tmp_5c & 0x3f]; + disk_nib_out(dsk, val, 8); + +/* 6440 */ + /* data epilog */ + disk_nib_out(dsk, 0xde, 8); /* epi */ + disk_nib_out(dsk, 0xaa, 8); /* epi */ + disk_nib_out(dsk, 0xff, 8); + } + + + disk_nib_end_track(dsk); + + if(g_check_nibblization) { + disk_check_nibblization(dsk, qtr_track, &(track_buf[0]), + unix_len); + } +} + +void +disk_4x4_nib_out(Disk *dsk, word32 val) +{ + disk_nib_out(dsk, 0xaa | (val >> 1), 8); + disk_nib_out(dsk, 0xaa | val, 8); +} + +void +disk_nib_out(Disk *dsk, byte val, int size) +{ + Track *trk; + int pos; + int old_size; + int track_len; + int overflow_size; + int qtr_track; + + + qtr_track = dsk->cur_qtr_track; + + trk = &(dsk->tracks[qtr_track]); + + track_len = trk->track_len; + + if(track_len <= 10) { + printf("Writing to an invalid qtr track: %02x!\n", qtr_track); + printf("name: %s, track_len: %08x, val: %08x, size: %d\n", + dsk->name_ptr, track_len, val, size); + exit(1); + return; + } + + trk->track_dirty = 1; + dsk->disk_dirty = 1; + + pos = trk->dsk->nib_pos; + overflow_size = trk->overflow_size; + if(pos >= track_len) { + pos = 0; + } + + old_size = trk->nib_area[pos]; + + + while(size >= (10 + old_size)) { + size = size - old_size; + pos += 2; + if(pos >= track_len) { + pos = 0; + } + old_size = trk->nib_area[pos]; + } + + if(size > 10) { + size = 10; + } + + if((val & 0x80) == 0) { + val |= 0x80; + } + + trk->nib_area[pos++] = size; + trk->nib_area[pos++] = val; + if(pos >= track_len) { + pos = 0; + } + + overflow_size += (size - old_size); + if((overflow_size > 8) && (size > 8)) { + overflow_size -= trk->nib_area[pos]; + trk->nib_area[pos++] = 0; + trk->nib_area[pos++] = 0; + if(pos >= track_len) { + pos = 0; + } + } else if(overflow_size < -64) { + halt_printf("overflow_sz:%03x, pos:%02x\n",overflow_size,pos); + } + + trk->dsk->nib_pos = pos; + trk->overflow_size = overflow_size; + + if((val & 0x80) == 0 || size < 8) { + halt_printf("disk_nib_out, wrote %02x, size: %d\n", val, size); + } +} + +void +disk_nib_end_track(Disk *dsk) +{ + int qtr_track; + + dsk->nib_pos = 0; + qtr_track = dsk->cur_qtr_track; + dsk->tracks[qtr_track].track_dirty = 0; + + dsk->disk_dirty = 0; +} + +void +iwm_show_track(int slot_drive, int track) +{ + Disk *dsk; + Track *trk; + int drive; + int sel35; + int qtr_track; + + if(slot_drive < 0) { + drive = iwm.drive_select; + sel35 = g_apple35_sel; + } else { + drive = slot_drive & 1; + sel35 = !((slot_drive >> 1) & 1); + } + + if(sel35) { + dsk = &(iwm.drive35[drive]); + } else { + dsk = &(iwm.drive525[drive]); + } + + if(track < 0) { + qtr_track = dsk->cur_qtr_track; + } else { + qtr_track = track; + } + trk = &(dsk->tracks[qtr_track]); + + if(trk->track_len <= 0) { + printf("Track_len: %d\n", trk->track_len); + printf("No track for type: %d, drive: %d, qtrk: %02x\n", + g_apple35_sel, drive, qtr_track); + return; + } + + printf("Current drive: %d, q_track: %02x\n", drive, qtr_track); + + iwm_show_a_track(trk); +} + +void +iwm_show_a_track(Track *trk) +{ + int sum; + int len; + int pos; + int i; + + printf(" Showtrack:dirty: %d, pos: %04x, ovfl: %04x, len: %04x\n", + trk->track_dirty, trk->dsk->nib_pos, + trk->overflow_size, trk->track_len); + + len = trk->track_len; + printf("Track len in bytes: %04x\n", len); + if(len >= 2*15000) { + len = 2*15000; + printf("len too big, using %04x\n", len); + } + + pos = 0; + for(i = 0; i < len; i += 16) { + printf("%04x: %2d,%02x %2d,%02x %2d,%02x %2d,%02x " + "%2d,%02x %2d,%02x %2d,%02x %2d,%02x\n", pos, + trk->nib_area[pos], trk->nib_area[pos+1], + trk->nib_area[pos+2], trk->nib_area[pos+3], + trk->nib_area[pos+4], trk->nib_area[pos+5], + trk->nib_area[pos+6], trk->nib_area[pos+7], + trk->nib_area[pos+8], trk->nib_area[pos+9], + trk->nib_area[pos+10], trk->nib_area[pos+11], + trk->nib_area[pos+12], trk->nib_area[pos+13], + trk->nib_area[pos+14], trk->nib_area[pos+15]); + pos += 16; + if(pos >= len) { + pos -= len; + } + } + + sum = 0; + for(i = 0; i < len; i += 2) { + sum += trk->nib_area[i]; + } + + printf("bit_sum: %d, expected: %d, overflow_size: %d\n", + sum, len*8/2, trk->overflow_size); +} + diff --git a/src/iwm.h b/src/iwm.h new file mode 100644 index 0000000..e9a6587 --- /dev/null +++ b/src/iwm.h @@ -0,0 +1,116 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_iwm_h[] = "@(#)$KmKId: iwm.h,v 1.13 2003-07-08 23:29:48-04 kentd Exp $"; +#endif + +#define MAX_TRACKS (2*80) +#define MAX_C7_DISKS 32 + +#define NIB_LEN_525 0x1900 /* 51072 bits per track */ +#define NIBS_FROM_ADDR_TO_DATA 20 + +#define DSK_TYPE_PRODOS 0 +#define DSK_TYPE_DOS33 1 +#define DSK_TYPE_NIB 2 + +typedef struct _Disk Disk; + +STRUCT(Track) { + Disk *dsk; + byte *nib_area; + int track_dirty; + int overflow_size; + int track_len; + int unix_pos; + int unix_len; +}; + +struct _Disk { + double dcycs_last_read; + char *name_ptr; + char *partition_name; + int partition_num; + int fd; + int force_size; + int image_start; + int image_size; + int smartport; + int disk_525; + int drive; + int cur_qtr_track; + int image_type; + int vol_num; + int write_prot; + int write_through_to_unix; + int disk_dirty; + int just_ejected; + int last_phase; + int nib_pos; + int num_tracks; + Track tracks[MAX_TRACKS]; +}; + + +STRUCT(Iwm) { + Disk drive525[2]; + Disk drive35[2]; + Disk smartport[MAX_C7_DISKS]; + int motor_on; + int motor_off; + int motor_off_vbl_count; + int motor_on35; + int head35; + int step_direction35; + int iwm_phase[4]; + int iwm_mode; + int drive_select; + int q6; + int q7; + int enable2; + int reset; + + word32 previous_write_val; + int previous_write_bits; +}; + + +STRUCT(Driver_desc) { + word16 sig; + word16 blk_size; + word32 blk_count; + word16 dev_type; + word16 dev_id; + word32 data; + word16 drvr_count; +}; + +STRUCT(Part_map) { + word16 sig; + word16 sigpad; + word32 map_blk_cnt; + word32 phys_part_start; + word32 part_blk_cnt; + char part_name[32]; + char part_type[32]; + word32 data_start; + word32 data_cnt; + word32 part_status; + word32 log_boot_start; + word32 boot_size; + word32 boot_load; + word32 boot_load2; + word32 boot_entry; + word32 boot_entry2; + word32 boot_cksum; + char processor[16]; + char junk[128]; +}; diff --git a/src/iwm_35_525.h b/src/iwm_35_525.h new file mode 100644 index 0000000..2604c42 --- /dev/null +++ b/src/iwm_35_525.h @@ -0,0 +1,310 @@ + +#ifdef INCLUDE_IWM_RCSID_C +const char rcsdif_iwm_35_525_h[] = "@(#)$KmKId: iwm_35_525.h,v 1.9 2002-11-14 01:03:16-05 kadickey Exp $"; +#endif + +int +IWM_READ_ROUT (Disk *dsk, int fast_disk_emul, double dcycs) +{ + Track *trk; + double dcycs_last_read; + int pos; + int pos2; + int size; + int next_size; + int qtr_track; + int skip_nibs; + int track_len; + byte ret; + int shift; + int skip; + int cycs_this_nib; + int cycs_passed; + double dcycs_this_nib; + double dcycs_next_nib; + double dcycs_passed; + double track_dcycs; + double dtmp; + + iwm.previous_write_bits = 0; + + qtr_track = dsk->cur_qtr_track; + + trk = &(dsk->tracks[qtr_track]); + track_len = trk->track_len; + + dcycs_last_read = dsk->dcycs_last_read; + dcycs_passed = dcycs - dcycs_last_read; + + pos = dsk->nib_pos; + if(pos >= track_len) { + /* Arm may have moved from inner 3.5 track to outer one, */ + /* and so must make pos fit on smaller sized track */ + pos = 0; + } + + cycs_passed = (int)dcycs_passed; + + if(track_len == 0) { + return (cycs_passed & 0x7f) + 0x80; + } + size = trk->nib_area[pos]; + + while(size == 0) { + pos += 2; + if(pos >= track_len) { + pos = 0; + } + size = trk->nib_area[pos]; + } + + cycs_this_nib = size * (2 * IWM_CYC_MULT); + dcycs_this_nib = (double)cycs_this_nib; + + if(fast_disk_emul) { + cycs_passed = cycs_this_nib; + dcycs_passed = dcycs_this_nib; + + /* pull a trick to make disk motor-on test pass ($bd34 RWTS) */ + /* if this would be a sync byte, and we didn't just do this */ + /* then don't return whole byte */ + /* BUT, don't do this if g_fast_disk_unnib, since it will */ + /* cause the dsk->unix routines to break */ + if(size > 8 && !g_fast_disk_unnib && (g_iwm_fake_fast == 0)) { + cycs_passed = cycs_passed >> 1; + dcycs_passed = dcycs_passed * 0.5; + g_iwm_fake_fast = 1; + } else { + g_iwm_fake_fast = 0; + } + } + + skip = 0; + if(cycs_passed >= (cycs_this_nib + 11)) { + /* skip some bits? */ + skip = 1; + if(iwm.iwm_mode & 1) { + /* latch mode */ + + pos2 = pos + 2; + if(pos2 >= track_len) { + pos2 = 0; + } + next_size = trk->nib_area[pos2]; + while(next_size == 0) { + pos2 += 2; + if(pos2 >= track_len) { + pos2 = 0; + } + next_size = trk->nib_area[pos2]; + } + + dcycs_next_nib = next_size * (2 * IWM_CYC_MULT); + + if(dcycs_passed < (dcycs_this_nib + dcycs_next_nib)) { + skip = 0; + } + } + } + + if(skip) { + iwm_printf("skip since cycs_passed: %f, cycs_this_nib: %f\n", + dcycs_passed, dcycs_this_nib); + + track_dcycs = IWM_CYC_MULT * (track_len * 8); + + if(dcycs_passed >= track_dcycs) { + dtmp = (int)(dcycs_passed / track_dcycs); + dcycs_passed = dcycs_passed - + (dtmp * track_dcycs); + dcycs_last_read += (dtmp * track_dcycs); + } + + if(dcycs_passed >= track_dcycs || dcycs_passed < 0.0) { + dcycs_passed = 0.0; + } + + cycs_passed = (int)dcycs_passed; + + skip_nibs = ((word32)cycs_passed) >> (4 + IWM_DISK_525); + + pos += skip_nibs * 2; + while(pos >= track_len) { + pos -= track_len; + } + + dcycs_last_read += (skip_nibs * 16 * IWM_CYC_MULT); + + dsk->dcycs_last_read = dcycs_last_read; + + size = trk->nib_area[pos]; + dcycs_passed = dcycs - dcycs_last_read; + if(dcycs_passed < 0.0 || dcycs_passed > 64.0) { + halt_printf("skip, last_read:%f, dcycs:%f, dcyc_p:%f\n", + dcycs_last_read, dcycs, dcycs_passed); + } + + while(size == 0) { + pos += 2; + if(pos >= track_len) { + pos = 0; + } + size = trk->nib_area[pos]; + } + + cycs_this_nib = size * (2 * IWM_CYC_MULT); + cycs_passed = (int)dcycs_passed; + dcycs_this_nib = cycs_this_nib; + } + + if(cycs_passed < cycs_this_nib) { + /* partial */ +#if 0 + iwm_printf("Disk partial, %f < %f, size: %d\n", + dcycs_passed, dcycs_this_nib, size); +#endif + shift = (cycs_passed) >> (1 + IWM_DISK_525); + ret = trk->nib_area[pos+1] >> (size - shift); + if(ret & 0x80) { + halt_printf("Bad shift in partial read: %02x, but " + "c_pass:%f, this_nib:%f, shift: %d, size: %d\n", + ret, dcycs_passed, dcycs_this_nib, shift, size); + } + } else { + /* whole thing */ + ret = trk->nib_area[pos+1]; + pos += 2; + if(pos >= track_len) { + pos = 0; + } + if(!fast_disk_emul) { + dsk->dcycs_last_read = dcycs_last_read + dcycs_this_nib; + } + } + + dsk->nib_pos = pos; + if(pos < 0 || pos > track_len) { + halt_printf("I just set nib_pos: %d!\n", pos); + } + +#if 0 + iwm_printf("Disk read, returning: %02x\n", ret); +#endif + + return ret; +} + + +void +IWM_WRITE_ROUT (Disk *dsk, word32 val, int fast_disk_emul, double dcycs) +{ + double dcycs_last_read; + word32 bits_read; + word32 mask; + word32 prev_val; + double dcycs_this_nib; + double dcycs_passed; + int sdiff; + int prev_bits; + + if(dsk->fd < 0) { + halt_printf("Tried to write to type: %d, drive: %d, fd: %d!\n", + IWM_DISK_525, dsk->drive, dsk->fd); + return; + } + + dcycs_last_read = dsk->dcycs_last_read; + + dcycs_passed = dcycs - dcycs_last_read; + + prev_val = iwm.previous_write_val; + prev_bits = iwm.previous_write_bits; + mask = 0x100; + iwm_printf("Iwm write: prev: %x,%d, new:%02x\n", prev_val, prev_bits, + val); + + if(IWM_DISK_525) { + /* Activate slow write emulation mode */ + g_dcycs_end_emul_wr = dcycs + 64.0; + if(!g_slow_525_emul_wr) { + set_halt(HALT_EVENT); + g_slow_525_emul_wr = 1; + } + } else { + /* disable slow writes on 3.5" drives */ + if(g_slow_525_emul_wr) { + set_halt(HALT_EVENT); + printf("HACK3: g_slow_525_emul_wr set to 0\n"); + g_slow_525_emul_wr = 0; + } + } + + if(iwm.iwm_mode & 2) { + /* async mode = 3.5" default */ + bits_read = 8; + } else { + /* sync mode, 5.25" drives */ + bits_read = ((int)dcycs_passed) >> (1 + IWM_DISK_525); + if(bits_read < 8) { + bits_read = 8; + } + } + + if(fast_disk_emul) { + bits_read = 8; + } + + dcycs_this_nib = bits_read * (2 * IWM_CYC_MULT); + + if(fast_disk_emul) { + dcycs_passed = dcycs_this_nib; + } + + if(prev_bits > 0) { + while((prev_val & 0x80) == 0 && bits_read > 0) { + /* previous byte needs some bits */ + mask = mask >> 1; + prev_val = (prev_val << 1) + ((val & mask) !=0); + prev_bits++; + bits_read--; + } + } + + val = val & (mask - 1); + if(prev_bits) { + /* force out prev_val if it had many bits before */ + /* this prevents writes of 0 from messing us up */ + if(((prev_val & 0x80) == 0) && (prev_bits < 10)) { + /* special case: we still don't have enough to go */ + iwm_printf("iwm_write: zip2: %02x, %d, left:%02x,%d\n", + prev_val, prev_bits, val,bits_read); + val = prev_val; + bits_read = prev_bits; + } else { + iwm_printf("iwm_write: prev: %02x, %d, left:%02x, %d\n", + prev_val, prev_bits, val, bits_read); + disk_nib_out(dsk, prev_val, prev_bits); + } + } else if(val & 0x80) { + iwm_printf("iwm_write: new: %02x, %d\n", val,bits_read); + disk_nib_out(dsk, val, bits_read); + bits_read = 0; + } else { + iwm_printf("iwm_write: zip: %02x, %d, left:%02x,%d\n", + prev_val, prev_bits, val,bits_read); + } + + iwm.previous_write_val = val; + iwm.previous_write_bits = bits_read; + if(bits_read < 0) { + halt_printf("iwm, bits_rd:%d, val:%08x, prev:%02x, prevb:%d\n", + bits_read, val, prev_val, prev_bits); + } + + sdiff = dcycs - dcycs_last_read; + if(sdiff < (dcycs_this_nib) || (sdiff > (2*dcycs_this_nib)) ) { + dsk->dcycs_last_read = dcycs; + } else { + dsk->dcycs_last_read = dcycs_last_read + dcycs_this_nib; + } +} diff --git a/src/joystick_driver.c b/src/joystick_driver.c new file mode 100644 index 0000000..35c106f --- /dev/null +++ b/src/joystick_driver.c @@ -0,0 +1,227 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_joystick_driver_c[] = "@(#)$KmKId: joystick_driver.c,v 1.7 2002-11-19 03:09:59-05 kadickey Exp $"; + +#include "defc.h" +#include + +#ifdef __linux__ +# include +#endif + +#ifdef _WIN32 +# include +# include +#endif + +extern int g_joystick_type; /* in paddles.c */ +extern int g_paddle_button[]; +extern int g_paddle_val[]; + + +const char *g_joystick_dev = "/dev/js0"; /* default joystick dev file */ +#define MAX_JOY_NAME 128 + +int g_joystick_fd = -1; +int g_joystick_num_axes = 0; +int g_joystick_num_buttons = 0; + + +#ifdef __linux__ +void +joystick_init() +{ + char joy_name[MAX_JOY_NAME]; + int version; + int fd; + int i; + + fd = open(g_joystick_dev, O_RDONLY | O_NONBLOCK); + if(fd < 0) { + printf("Unable to open joystick dev file: %s, errno: %d\n", + g_joystick_dev, errno); + printf("Defaulting to mouse joystick\n"); + return; + } + + strcpy(&joy_name[0], "Unknown Joystick"); + version = 0x800; + + ioctl(fd, JSIOCGNAME(MAX_JOY_NAME), &joy_name[0]); + ioctl(fd, JSIOCGAXES, &g_joystick_num_axes); + ioctl(fd, JSIOCGBUTTONS, &g_joystick_num_buttons); + ioctl(fd, JSIOCGVERSION, &version); + + printf("Detected joystick: %s [%d axes, %d buttons vers: %08x]\n", + joy_name, g_joystick_num_axes, g_joystick_num_buttons, + version); + + g_joystick_type = JOYSTICK_LINUX; + g_joystick_fd = fd; + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 280; + g_paddle_button[i] = 1; + } + + joystick_update(); +} + +/* joystick_update_linux() called from paddles.c. Update g_paddle_val[] */ +/* and g_paddle_button[] arrays with current information */ +void +joystick_update() +{ + struct js_event js; /* the linux joystick event record */ + int val; + int num; + int type; + int ret; + int len; + int i; + + /* suck up to 20 events, then give up */ + len = sizeof(struct js_event); + for(i = 0; i < 20; i++) { + ret = read(g_joystick_fd, &js, len); + if(ret != len) { + /* just get out */ + return; + } + type = js.type & ~JS_EVENT_INIT; + val = js.value; + num = js.number & 3; /* clamp to 0-3 */ + switch(type) { + case JS_EVENT_BUTTON: + g_paddle_button[num] = val; + break; + case JS_EVENT_AXIS: + /* val is -32767 to +32767, convert to 0->280 */ + /* want just 255, but go a little over for robustness*/ + g_paddle_val[num] = ((val + 32767) * 9) >> 11; + break; + } + } +} + +void +joystick_update_button() +{ +} + +#else /* !__linux__ */ + +# ifdef _WIN32 +void +joystick_init() +{ + JOYINFO info; + JOYCAPS joycap; + MMRESULT ret1, ret2; + int i; + + // Check that there is a joystick device + if(joyGetNumDevs() <= 0) { + printf("--No joystick hardware detected\n"); + return; + } + + // Check that at least joystick 1 or joystick 2 is available + ret1 = joyGetPos(JOYSTICKID1, &info); + ret2 = joyGetDevCaps(JOYSTICKID1, &joycap, sizeof(joycap)); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_joystick_type = JOYSTICK_WIN32_1; + printf("--Joystick #1 = %s\n", joycap.szPname); + } else { + ret1 = joyGetPos(JOYSTICKID2, &info); + ret2 = joyGetDevCaps(JOYSTICKID2, &joycap, sizeof(joycap)); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_joystick_type = JOYSTICK_WIN32_2; + printf("--Joystick #2 = %s\n", joycap.szPname); + } else { + printf("No joysticks found...\n"); + g_joystick_type = JOYSTICK_MOUSE; + return; + } + + } + + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 280; + g_paddle_button[i] = 1; + } + + joystick_update(); +} + +void +joystick_update() +{ + JOYCAPS joycap; + JOYINFO info; + UINT id; + MMRESULT ret1, ret2; + + id = JOYSTICKID1; + if(g_joystick_type == JOYSTICK_WIN32_2) { + id = JOYSTICKID2; + } + + ret1 = joyGetDevCaps(id, &joycap, sizeof(joycap)); + ret2 = joyGetPos(id, &info); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_paddle_val[0] = (info.wXpos - joycap.wXmin) * 280 / + (joycap.wXmax - joycap.wXmin); + g_paddle_val[1] = (info.wYpos - joycap.wYmin) * 280 / + (joycap.wYmax - joycap.wYmin); + g_paddle_button[0] = ((info.wButtons & JOY_BUTTON1) ? 1 : 0); + g_paddle_button[1] = ((info.wButtons & JOY_BUTTON2) ? 1 : 0); + } +} + +void +joystick_update_button() +{ + JOYINFOEX info; + UINT id; + + id = JOYSTICKID1; + if(g_joystick_type == JOYSTICK_WIN32_2) { + id = JOYSTICKID2; + } + + info.dwSize = sizeof(JOYINFOEX); + info.dwFlags = JOY_RETURNBUTTONS; + if(joyGetPosEx(id, &info) == JOYERR_NOERROR) { + g_paddle_button[0] = ((info.dwButtons & JOY_BUTTON1) ? 1 : 0); + g_paddle_button[1] = ((info.dwButtons & JOY_BUTTON2) ? 1 : 0); + } +} +# else + +/* stubs for the routines */ +void +joystick_init() +{ + printf("No joy with joystick\n"); +} + +void +joystick_update() +{ +} + +void +joystick_update_button() +{ +} + +# endif /* !WIN32 */ +#endif diff --git a/src/kegsfont.h b/src/kegsfont.h new file mode 100644 index 0000000..d4394a7 --- /dev/null +++ b/src/kegsfont.h @@ -0,0 +1,514 @@ +/* $KmKId: kegsfont.h,v 1.1 2002-11-10 03:31:51-05 kadickey Exp $ */ + +/* char 0x00 (raw 0x40) */ + { 0xc7, 0xbb, 0xab, 0xa3, 0xa7, 0xbf, 0xc3, 0xff }, +/* char 0x01 (raw 0x41) */ + { 0xef, 0xd7, 0xbb, 0xbb, 0x83, 0xbb, 0xbb, 0xff }, +/* char 0x02 (raw 0x42) */ + { 0x87, 0xbb, 0xbb, 0x87, 0xbb, 0xbb, 0x87, 0xff }, +/* char 0x03 (raw 0x43) */ + { 0xc7, 0xbb, 0xbf, 0xbf, 0xbf, 0xbb, 0xc7, 0xff }, +/* char 0x04 (raw 0x44) */ + { 0x87, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x87, 0xff }, +/* char 0x05 (raw 0x45) */ + { 0x83, 0xbf, 0xbf, 0x87, 0xbf, 0xbf, 0x83, 0xff }, +/* char 0x06 (raw 0x46) */ + { 0x83, 0xbf, 0xbf, 0x87, 0xbf, 0xbf, 0xbf, 0xff }, +/* char 0x07 (raw 0x47) */ + { 0xc3, 0xbf, 0xbf, 0xbf, 0xb3, 0xbb, 0xc3, 0xff }, +/* char 0x08 (raw 0x48) */ + { 0xbb, 0xbb, 0xbb, 0x83, 0xbb, 0xbb, 0xbb, 0xff }, +/* char 0x09 (raw 0x49) */ + { 0xc7, 0xef, 0xef, 0xef, 0xef, 0xef, 0xc7, 0xff }, +/* char 0x0a (raw 0x4a) */ + { 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xc7, 0xff }, +/* char 0x0b (raw 0x4b) */ + { 0xbb, 0xb7, 0xaf, 0x9f, 0xaf, 0xb7, 0xbb, 0xff }, +/* char 0x0c (raw 0x4c) */ + { 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x83, 0xff }, +/* char 0x0d (raw 0x4d) */ + { 0xbb, 0x93, 0xab, 0xab, 0xbb, 0xbb, 0xbb, 0xff }, +/* char 0x0e (raw 0x4e) */ + { 0xbb, 0xbb, 0x9b, 0xab, 0xb3, 0xbb, 0xbb, 0xff }, +/* char 0x0f (raw 0x4f) */ + { 0xc7, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xc7, 0xff }, +/* char 0x10 (raw 0x50) */ + { 0x87, 0xbb, 0xbb, 0x87, 0xbf, 0xbf, 0xbf, 0xff }, +/* char 0x11 (raw 0x51) */ + { 0xc7, 0xbb, 0xbb, 0xbb, 0xab, 0xb7, 0xcb, 0xff }, +/* char 0x12 (raw 0x52) */ + { 0x87, 0xbb, 0xbb, 0x87, 0xaf, 0xb7, 0xbb, 0xff }, +/* char 0x13 (raw 0x53) */ + { 0xc7, 0xbb, 0xbf, 0xc7, 0xfb, 0xbb, 0xc7, 0xff }, +/* char 0x14 (raw 0x54) */ + { 0x83, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xff }, +/* char 0x15 (raw 0x55) */ + { 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xc7, 0xff }, +/* char 0x16 (raw 0x56) */ + { 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xd7, 0xef, 0xff }, +/* char 0x17 (raw 0x57) */ + { 0xbb, 0xbb, 0xbb, 0xab, 0xab, 0x93, 0xbb, 0xff }, +/* char 0x18 (raw 0x58) */ + { 0xbb, 0xbb, 0xd7, 0xef, 0xd7, 0xbb, 0xbb, 0xff }, +/* char 0x19 (raw 0x59) */ + { 0xbb, 0xbb, 0xd7, 0xef, 0xef, 0xef, 0xef, 0xff }, +/* char 0x1a (raw 0x5a) */ + { 0x83, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x83, 0xff }, +/* char 0x1b (raw 0x5b) */ + { 0x83, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x83, 0xff }, +/* char 0x1c (raw 0x5c) */ + { 0xff, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xff, 0xff }, +/* char 0x1d (raw 0x5d) */ + { 0x83, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0x83, 0xff }, +/* char 0x1e (raw 0x5e) */ + { 0xff, 0xff, 0xef, 0xd7, 0xbb, 0xff, 0xff, 0xff }, +/* char 0x1f (raw 0x5f) */ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 }, +/* char 0x20 (raw 0x20) */ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, +/* char 0x21 (raw 0x21) */ + { 0xef, 0xef, 0xef, 0xef, 0xef, 0xff, 0xef, 0xff }, +/* char 0x22 (raw 0x22) */ + { 0xd7, 0xd7, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff }, +/* char 0x23 (raw 0x23) */ + { 0xd7, 0xd7, 0x83, 0xd7, 0x83, 0xd7, 0xd7, 0xff }, +/* char 0x24 (raw 0x24) */ + { 0xef, 0xc3, 0xaf, 0xc7, 0xeb, 0x87, 0xef, 0xff }, +/* char 0x25 (raw 0x25) */ + { 0x9f, 0x9b, 0xf7, 0xef, 0xdf, 0xb3, 0xf3, 0xff }, +/* char 0x26 (raw 0x26) */ + { 0xdf, 0xaf, 0xaf, 0xdf, 0xab, 0xb7, 0xcb, 0xff }, +/* char 0x27 (raw 0x27) */ + { 0xef, 0xef, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff }, +/* char 0x28 (raw 0x28) */ + { 0xef, 0xdf, 0xbf, 0xbf, 0xbf, 0xdf, 0xef, 0xff }, +/* char 0x29 (raw 0x29) */ + { 0xef, 0xf7, 0xfb, 0xfb, 0xfb, 0xf7, 0xef, 0xff }, +/* char 0x2a (raw 0x2a) */ + { 0xef, 0xab, 0xc7, 0xef, 0xc7, 0xab, 0xef, 0xff }, +/* char 0x2b (raw 0x2b) */ + { 0xff, 0xef, 0xef, 0x83, 0xef, 0xef, 0xff, 0xff }, +/* char 0x2c (raw 0x2c) */ + { 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xdf, 0xff }, +/* char 0x2d (raw 0x2d) */ + { 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff }, +/* char 0x2e (raw 0x2e) */ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff }, +/* char 0x2f (raw 0x2f) */ + { 0xff, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0xff, 0xff }, +/* char 0x30 (raw 0x30) */ + { 0xc7, 0xbb, 0xb3, 0xab, 0x9b, 0xbb, 0xc7, 0xff }, +/* char 0x31 (raw 0x31) */ + { 0xef, 0xcf, 0xef, 0xef, 0xef, 0xef, 0xc7, 0xff }, +/* char 0x32 (raw 0x32) */ + { 0xc7, 0xbb, 0xfb, 0xe7, 0xdf, 0xbf, 0x83, 0xff }, +/* char 0x33 (raw 0x33) */ + { 0x83, 0xfb, 0xf7, 0xe7, 0xfb, 0xbb, 0xc7, 0xff }, +/* char 0x34 (raw 0x34) */ + { 0xf7, 0xe7, 0xd7, 0xb7, 0x83, 0xf7, 0xf7, 0xff }, +/* char 0x35 (raw 0x35) */ + { 0x83, 0xbf, 0x87, 0xfb, 0xfb, 0xbb, 0xc7, 0xff }, +/* char 0x36 (raw 0x36) */ + { 0xe3, 0xdf, 0xbf, 0x87, 0xbb, 0xbb, 0xc7, 0xff }, +/* char 0x37 (raw 0x37) */ + { 0x83, 0xfb, 0xf7, 0xef, 0xdf, 0xdf, 0xdf, 0xff }, +/* char 0x38 (raw 0x38) */ + { 0xc7, 0xbb, 0xbb, 0xc7, 0xbb, 0xbb, 0xc7, 0xff }, +/* char 0x39 (raw 0x39) */ + { 0xc7, 0xbb, 0xbb, 0xc3, 0xfb, 0xf7, 0x8f, 0xff }, +/* char 0x3a (raw 0x3a) */ + { 0xff, 0xff, 0xef, 0xff, 0xef, 0xff, 0xff, 0xff }, +/* char 0x3b (raw 0x3b) */ + { 0xff, 0xff, 0xef, 0xff, 0xef, 0xef, 0xdf, 0xff }, +/* char 0x3c (raw 0x3c) */ + { 0xf7, 0xef, 0xdf, 0xbf, 0xdf, 0xef, 0xf7, 0xff }, +/* char 0x3d (raw 0x3d) */ + { 0xff, 0xff, 0x83, 0xff, 0x83, 0xff, 0xff, 0xff }, +/* char 0x3e (raw 0x3e) */ + { 0xdf, 0xef, 0xf7, 0xfb, 0xf7, 0xef, 0xdf, 0xff }, +/* char 0x3f (raw 0x3f) */ + { 0xc7, 0xbb, 0xf7, 0xef, 0xef, 0xff, 0xef, 0xff }, +/* char 0x40 (raw 0x14) */ + { 0x08, 0x10, 0x6c, 0xfe, 0xfc, 0xfc, 0x7e, 0x6c }, +/* char 0x41 (raw 0x11) */ + { 0x08, 0x10, 0x6c, 0x82, 0x84, 0x84, 0x52, 0x6c }, +/* char 0x42 (raw 0xf5) */ + { 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x6c, 0x42 }, +/* char 0x43 (raw 0x82) */ + { 0xfe, 0x44, 0x28, 0x10, 0x10, 0x28, 0x54, 0xfe }, +/* char 0x44 (raw 0xeb) */ + { 0x00, 0x02, 0x04, 0x88, 0x50, 0x20, 0x20, 0x00 }, +/* char 0x45 (raw 0xe4) */ + { 0xfe, 0xfc, 0xfa, 0x36, 0xae, 0xde, 0xde, 0xfe }, +/* char 0x46 (raw 0xec) */ + { 0xfc, 0xfc, 0xfc, 0xdc, 0x9c, 0x00, 0x9e, 0xde }, +/* char 0x47 (raw 0xed) */ + { 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe }, +/* char 0x48 (raw 0xee) */ + { 0x10, 0x20, 0x40, 0xfe, 0x40, 0x20, 0x10, 0x00 }, +/* char 0x49 (raw 0xe9) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54 }, +/* char 0x4a (raw 0xef) */ + { 0x10, 0x10, 0x10, 0x10, 0x92, 0x54, 0x38, 0x10 }, +/* char 0x4b (raw 0xf0) */ + { 0x10, 0x38, 0x54, 0x92, 0x10, 0x10, 0x10, 0x10 }, +/* char 0x4c (raw 0xf1) */ + { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +/* char 0x4d (raw 0xf7) */ + { 0x02, 0x02, 0x02, 0x22, 0x62, 0xfe, 0x60, 0x20 }, +/* char 0x4e (raw 0xf6) */ + { 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc }, +/* char 0x4f (raw 0xaf) */ + { 0xc8, 0x18, 0x38, 0x7e, 0x38, 0x18, 0x08, 0xf6 }, +/* char 0x50 (raw 0xb8) */ + { 0x26, 0x30, 0x38, 0xfc, 0x38, 0x30, 0x20, 0xde }, +/* char 0x51 (raw 0xce) */ + { 0x02, 0x12, 0x10, 0xfe, 0x7c, 0x38, 0x12, 0x02 }, +/* char 0x52 (raw 0xe5) */ + { 0x02, 0x12, 0x38, 0x7c, 0xfe, 0x10, 0x12, 0x02 }, +/* char 0x53 (raw 0xea) */ + { 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00 }, +/* char 0x54 (raw 0xe6) */ + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xfe }, +/* char 0x55 (raw 0xe8) */ + { 0x10, 0x08, 0x04, 0xfe, 0x04, 0x08, 0x10, 0x00 }, +/* char 0x56 (raw 0xd7) */ + { 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa }, +/* char 0x57 (raw 0xe3) */ + { 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54 }, +/* char 0x58 (raw 0xf4) */ + { 0x00, 0x7c, 0x82, 0x80, 0x80, 0x80, 0xfe, 0x00 }, +/* char 0x59 (raw 0xe7) */ + { 0x00, 0x00, 0xfc, 0x02, 0x02, 0x02, 0xfe, 0x00 }, +/* char 0x5a (raw 0xf3) */ + { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, +/* char 0x5b (raw 0xd2) */ + { 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00 }, +/* char 0x5c (raw 0xc7) */ + { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe }, +/* char 0x5d (raw 0xd4) */ + { 0x28, 0x28, 0xee, 0x00, 0xee, 0x28, 0x28, 0x00 }, +/* char 0x5e (raw 0xdf) */ + { 0xfe, 0x02, 0x02, 0x32, 0x32, 0x02, 0x02, 0xfe }, +/* char 0x5f (raw 0xd1) */ + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, +/* char 0x60 (raw 0x60) */ + { 0xdf, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff }, +/* char 0x61 (raw 0x61) */ + { 0xff, 0xff, 0xc7, 0xfb, 0xc3, 0xbb, 0xc3, 0xff }, +/* char 0x62 (raw 0x62) */ + { 0xbf, 0xbf, 0x87, 0xbb, 0xbb, 0xbb, 0x87, 0xff }, +/* char 0x63 (raw 0x63) */ + { 0xff, 0xff, 0xc3, 0xbf, 0xbf, 0xbf, 0xc3, 0xff }, +/* char 0x64 (raw 0x64) */ + { 0xfb, 0xfb, 0xc3, 0xbb, 0xbb, 0xbb, 0xc3, 0xff }, +/* char 0x65 (raw 0x65) */ + { 0xff, 0xff, 0xc7, 0xbb, 0x83, 0xbf, 0xc3, 0xff }, +/* char 0x66 (raw 0x66) */ + { 0xe7, 0xdb, 0xdf, 0x87, 0xdf, 0xdf, 0xdf, 0xff }, +/* char 0x67 (raw 0x67) */ + { 0xff, 0xff, 0xc7, 0xbb, 0xbb, 0xc3, 0xfb, 0xc7 }, +/* char 0x68 (raw 0x68) */ + { 0xbf, 0xbf, 0x87, 0xbb, 0xbb, 0xbb, 0xbb, 0xff }, +/* char 0x69 (raw 0x69) */ + { 0xef, 0xff, 0xcf, 0xef, 0xef, 0xef, 0xc7, 0xff }, +/* char 0x6a (raw 0x6a) */ + { 0xf7, 0xff, 0xe7, 0xf7, 0xf7, 0xf7, 0xb7, 0xcf }, +/* char 0x6b (raw 0x6b) */ + { 0xbf, 0xbf, 0xbb, 0xb7, 0x8f, 0xb7, 0xbb, 0xff }, +/* char 0x6c (raw 0x6c) */ + { 0xcf, 0xef, 0xef, 0xef, 0xef, 0xef, 0xc7, 0xff }, +/* char 0x6d (raw 0x6d) */ + { 0xff, 0xff, 0x93, 0xab, 0xab, 0xab, 0xbb, 0xff }, +/* char 0x6e (raw 0x6e) */ + { 0xff, 0xff, 0x87, 0xbb, 0xbb, 0xbb, 0xbb, 0xff }, +/* char 0x6f (raw 0x6f) */ + { 0xff, 0xff, 0xc7, 0xbb, 0xbb, 0xbb, 0xc7, 0xff }, +/* char 0x70 (raw 0x70) */ + { 0xff, 0xff, 0x87, 0xbb, 0xbb, 0x87, 0xbf, 0xbf }, +/* char 0x71 (raw 0x71) */ + { 0xff, 0xff, 0xc3, 0xbb, 0xbb, 0xc3, 0xfb, 0xfb }, +/* char 0x72 (raw 0x72) */ + { 0xff, 0xff, 0xa3, 0x9f, 0xbf, 0xbf, 0xbf, 0xff }, +/* char 0x73 (raw 0x73) */ + { 0xff, 0xff, 0xc3, 0xbf, 0xc7, 0xfb, 0x87, 0xff }, +/* char 0x74 (raw 0x74) */ + { 0xdf, 0xdf, 0x87, 0xdf, 0xdf, 0xdb, 0xe7, 0xff }, +/* char 0x75 (raw 0x75) */ + { 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xb3, 0xcb, 0xff }, +/* char 0x76 (raw 0x76) */ + { 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xd7, 0xef, 0xff }, +/* char 0x77 (raw 0x77) */ + { 0xff, 0xff, 0xbb, 0xbb, 0xab, 0xab, 0x93, 0xff }, +/* char 0x78 (raw 0x78) */ + { 0xff, 0xff, 0xbb, 0xd7, 0xef, 0xd7, 0xbb, 0xff }, +/* char 0x79 (raw 0x79) */ + { 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xc3, 0xfb, 0xc7 }, +/* char 0x7a (raw 0x7a) */ + { 0xff, 0xff, 0x83, 0xf7, 0xef, 0xdf, 0x83, 0xff }, +/* char 0x7b (raw 0x7b) */ + { 0xe3, 0xcf, 0xcf, 0x9f, 0xcf, 0xcf, 0xe3, 0xff }, +/* char 0x7c (raw 0x7c) */ + { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef }, +/* char 0x7d (raw 0x7d) */ + { 0x8f, 0xe7, 0xe7, 0xf3, 0xe7, 0xe7, 0x8f, 0xff }, +/* char 0x7e (raw 0x7e) */ + { 0xcb, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, +/* char 0x7f (raw 0x7f) */ + { 0xff, 0xab, 0xd7, 0xab, 0xd7, 0xab, 0xff, 0xff }, +/* char 0x80 (raw 0x40) */ + { 0x38, 0x44, 0x54, 0x5c, 0x58, 0x40, 0x3c, 0x00 }, +/* char 0x81 (raw 0x41) */ + { 0x10, 0x28, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00 }, +/* char 0x82 (raw 0x42) */ + { 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 }, +/* char 0x83 (raw 0x43) */ + { 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00 }, +/* char 0x84 (raw 0x44) */ + { 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00 }, +/* char 0x85 (raw 0x45) */ + { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00 }, +/* char 0x86 (raw 0x46) */ + { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00 }, +/* char 0x87 (raw 0x47) */ + { 0x3c, 0x40, 0x40, 0x40, 0x4c, 0x44, 0x3c, 0x00 }, +/* char 0x88 (raw 0x48) */ + { 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00 }, +/* char 0x89 (raw 0x49) */ + { 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 }, +/* char 0x8a (raw 0x4a) */ + { 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00 }, +/* char 0x8b (raw 0x4b) */ + { 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00 }, +/* char 0x8c (raw 0x4c) */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00 }, +/* char 0x8d (raw 0x4d) */ + { 0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00 }, +/* char 0x8e (raw 0x4e) */ + { 0x44, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x00 }, +/* char 0x8f (raw 0x4f) */ + { 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 }, +/* char 0x90 (raw 0x50) */ + { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 }, +/* char 0x91 (raw 0x51) */ + { 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00 }, +/* char 0x92 (raw 0x52) */ + { 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00 }, +/* char 0x93 (raw 0x53) */ + { 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00 }, +/* char 0x94 (raw 0x54) */ + { 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 }, +/* char 0x95 (raw 0x55) */ + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 }, +/* char 0x96 (raw 0x56) */ + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 }, +/* char 0x97 (raw 0x57) */ + { 0x44, 0x44, 0x44, 0x54, 0x54, 0x6c, 0x44, 0x00 }, +/* char 0x98 (raw 0x58) */ + { 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00 }, +/* char 0x99 (raw 0x59) */ + { 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00 }, +/* char 0x9a (raw 0x5a) */ + { 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00 }, +/* char 0x9b (raw 0x5b) */ + { 0x7c, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7c, 0x00 }, +/* char 0x9c (raw 0x5c) */ + { 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00 }, +/* char 0x9d (raw 0x5d) */ + { 0x7c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x00 }, +/* char 0x9e (raw 0x5e) */ + { 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00 }, +/* char 0x9f (raw 0x5f) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe }, +/* char 0xa0 (raw 0x20) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +/* char 0xa1 (raw 0x21) */ + { 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00 }, +/* char 0xa2 (raw 0x22) */ + { 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00 }, +/* char 0xa3 (raw 0x23) */ + { 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00 }, +/* char 0xa4 (raw 0x24) */ + { 0x10, 0x3c, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00 }, +/* char 0xa5 (raw 0x25) */ + { 0x60, 0x64, 0x08, 0x10, 0x20, 0x4c, 0x0c, 0x00 }, +/* char 0xa6 (raw 0x26) */ + { 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00 }, +/* char 0xa7 (raw 0x27) */ + { 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }, +/* char 0xa8 (raw 0x28) */ + { 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00 }, +/* char 0xa9 (raw 0x29) */ + { 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00 }, +/* char 0xaa (raw 0x2a) */ + { 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10, 0x00 }, +/* char 0xab (raw 0x2b) */ + { 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00 }, +/* char 0xac (raw 0x2c) */ + { 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00 }, +/* char 0xad (raw 0x2d) */ + { 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00 }, +/* char 0xae (raw 0x2e) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00 }, +/* char 0xaf (raw 0x2f) */ + { 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00 }, +/* char 0xb0 (raw 0x30) */ + { 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00 }, +/* char 0xb1 (raw 0x31) */ + { 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 }, +/* char 0xb2 (raw 0x32) */ + { 0x38, 0x44, 0x04, 0x18, 0x20, 0x40, 0x7c, 0x00 }, +/* char 0xb3 (raw 0x33) */ + { 0x7c, 0x04, 0x08, 0x18, 0x04, 0x44, 0x38, 0x00 }, +/* char 0xb4 (raw 0x34) */ + { 0x08, 0x18, 0x28, 0x48, 0x7c, 0x08, 0x08, 0x00 }, +/* char 0xb5 (raw 0x35) */ + { 0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00 }, +/* char 0xb6 (raw 0x36) */ + { 0x1c, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00 }, +/* char 0xb7 (raw 0x37) */ + { 0x7c, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00 }, +/* char 0xb8 (raw 0x38) */ + { 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00 }, +/* char 0xb9 (raw 0x39) */ + { 0x38, 0x44, 0x44, 0x3c, 0x04, 0x08, 0x70, 0x00 }, +/* char 0xba (raw 0x3a) */ + { 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00 }, +/* char 0xbb (raw 0x3b) */ + { 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x20, 0x00 }, +/* char 0xbc (raw 0x3c) */ + { 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00 }, +/* char 0xbd (raw 0x3d) */ + { 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00 }, +/* char 0xbe (raw 0x3e) */ + { 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00 }, +/* char 0xbf (raw 0x3f) */ + { 0x38, 0x44, 0x08, 0x10, 0x10, 0x00, 0x10, 0x00 }, +/* char 0xc0 (raw 0x40) */ + { 0x38, 0x44, 0x54, 0x5c, 0x58, 0x40, 0x3c, 0x00 }, +/* char 0xc1 (raw 0x41) */ + { 0x10, 0x28, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00 }, +/* char 0xc2 (raw 0x42) */ + { 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 }, +/* char 0xc3 (raw 0x43) */ + { 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00 }, +/* char 0xc4 (raw 0x44) */ + { 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00 }, +/* char 0xc5 (raw 0x45) */ + { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x00 }, +/* char 0xc6 (raw 0x46) */ + { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00 }, +/* char 0xc7 (raw 0x47) */ + { 0x3c, 0x40, 0x40, 0x40, 0x4c, 0x44, 0x3c, 0x00 }, +/* char 0xc8 (raw 0x48) */ + { 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00 }, +/* char 0xc9 (raw 0x49) */ + { 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 }, +/* char 0xca (raw 0x4a) */ + { 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00 }, +/* char 0xcb (raw 0x4b) */ + { 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00 }, +/* char 0xcc (raw 0x4c) */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00 }, +/* char 0xcd (raw 0x4d) */ + { 0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00 }, +/* char 0xce (raw 0x4e) */ + { 0x44, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x00 }, +/* char 0xcf (raw 0x4f) */ + { 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 }, +/* char 0xd0 (raw 0x50) */ + { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 }, +/* char 0xd1 (raw 0x51) */ + { 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00 }, +/* char 0xd2 (raw 0x52) */ + { 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00 }, +/* char 0xd3 (raw 0x53) */ + { 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00 }, +/* char 0xd4 (raw 0x54) */ + { 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 }, +/* char 0xd5 (raw 0x55) */ + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 }, +/* char 0xd6 (raw 0x56) */ + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 }, +/* char 0xd7 (raw 0x57) */ + { 0x44, 0x44, 0x44, 0x54, 0x54, 0x6c, 0x44, 0x00 }, +/* char 0xd8 (raw 0x58) */ + { 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00 }, +/* char 0xd9 (raw 0x59) */ + { 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00 }, +/* char 0xda (raw 0x5a) */ + { 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00 }, +/* char 0xdb (raw 0x5b) */ + { 0x7c, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7c, 0x00 }, +/* char 0xdc (raw 0x5c) */ + { 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00 }, +/* char 0xdd (raw 0x5d) */ + { 0x7c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x00 }, +/* char 0xde (raw 0x5e) */ + { 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00 }, +/* char 0xdf (raw 0x5f) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe }, +/* char 0xe0 (raw 0x60) */ + { 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, +/* char 0xe1 (raw 0x61) */ + { 0x00, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00 }, +/* char 0xe2 (raw 0x62) */ + { 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00 }, +/* char 0xe3 (raw 0x63) */ + { 0x00, 0x00, 0x3c, 0x40, 0x40, 0x40, 0x3c, 0x00 }, +/* char 0xe4 (raw 0x64) */ + { 0x04, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x3c, 0x00 }, +/* char 0xe5 (raw 0x65) */ + { 0x00, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00 }, +/* char 0xe6 (raw 0x66) */ + { 0x18, 0x24, 0x20, 0x78, 0x20, 0x20, 0x20, 0x00 }, +/* char 0xe7 (raw 0x67) */ + { 0x00, 0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x38 }, +/* char 0xe8 (raw 0x68) */ + { 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00 }, +/* char 0xe9 (raw 0x69) */ + { 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00 }, +/* char 0xea (raw 0x6a) */ + { 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x48, 0x30 }, +/* char 0xeb (raw 0x6b) */ + { 0x40, 0x40, 0x44, 0x48, 0x70, 0x48, 0x44, 0x00 }, +/* char 0xec (raw 0x6c) */ + { 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00 }, +/* char 0xed (raw 0x6d) */ + { 0x00, 0x00, 0x6c, 0x54, 0x54, 0x54, 0x44, 0x00 }, +/* char 0xee (raw 0x6e) */ + { 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00 }, +/* char 0xef (raw 0x6f) */ + { 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 }, +/* char 0xf0 (raw 0x70) */ + { 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40 }, +/* char 0xf1 (raw 0x71) */ + { 0x00, 0x00, 0x3c, 0x44, 0x44, 0x3c, 0x04, 0x04 }, +/* char 0xf2 (raw 0x72) */ + { 0x00, 0x00, 0x5c, 0x60, 0x40, 0x40, 0x40, 0x00 }, +/* char 0xf3 (raw 0x73) */ + { 0x00, 0x00, 0x3c, 0x40, 0x38, 0x04, 0x78, 0x00 }, +/* char 0xf4 (raw 0x74) */ + { 0x20, 0x20, 0x78, 0x20, 0x20, 0x24, 0x18, 0x00 }, +/* char 0xf5 (raw 0x75) */ + { 0x00, 0x00, 0x44, 0x44, 0x44, 0x4c, 0x34, 0x00 }, +/* char 0xf6 (raw 0x76) */ + { 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 }, +/* char 0xf7 (raw 0x77) */ + { 0x00, 0x00, 0x44, 0x44, 0x54, 0x54, 0x6c, 0x00 }, +/* char 0xf8 (raw 0x78) */ + { 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 }, +/* char 0xf9 (raw 0x79) */ + { 0x00, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x38 }, +/* char 0xfa (raw 0x7a) */ + { 0x00, 0x00, 0x7c, 0x08, 0x10, 0x20, 0x7c, 0x00 }, +/* char 0xfb (raw 0x7b) */ + { 0x1c, 0x30, 0x30, 0x60, 0x30, 0x30, 0x1c, 0x00 }, +/* char 0xfc (raw 0x7c) */ + { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, +/* char 0xfd (raw 0x7d) */ + { 0x70, 0x18, 0x18, 0x0c, 0x18, 0x18, 0x70, 0x00 }, +/* char 0xfe (raw 0x7e) */ + { 0x34, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +/* char 0xff (raw 0x7f) */ + { 0x00, 0x54, 0x28, 0x54, 0x28, 0x54, 0x00, 0x00 }, diff --git a/src/kegsicon.icns b/src/kegsicon.icns new file mode 100644 index 0000000..72ea172 Binary files /dev/null and b/src/kegsicon.icns differ diff --git a/src/macdriver.c b/src/macdriver.c new file mode 100644 index 0000000..bc113f4 --- /dev/null +++ b/src/macdriver.c @@ -0,0 +1,955 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_macdriver_c[] = "@(#)$KmKId: macdriver.c,v 1.19 2004-03-23 17:27:56-05 kentd Exp $"; + +// Quartz: CreateCGContextForPort vs QDBeginCGContext + +// Use CGDisplayMoveCursorToPoint(kCGDirectMainDisplay) to warp pointer +// Use CGPointMake to get a point + +#include + +#include "defc.h" +#include "protos_macdriver.h" + +#define MAX_STATUS_LINES 7 +#define X_LINE_LENGTH 88 +#define MAX_MAC_ARGS 128 + +WindowRef g_main_window; +int g_quit_seen = 0; +EventHandlerUPP g_quit_handler_UPP; +EventHandlerUPP g_dummy_event_handler_UPP; +RgnHandle g_event_rgnhandle = 0; +int g_ignore_next_click = 0; +int g_mainwin_active = 0; +GDHandle g_gdhandle = 0; +int g_mac_mouse_x = 0; +int g_mac_mouse_y = 0; + +FMFontFamily g_status_font_family; + +extern Kimage g_mainwin_kimage; + +int g_mac_argc = 0; +char *g_mac_argv[MAX_MAC_ARGS]; +word32 g_mac_shift_control_state = 0; +extern char g_argv0_path[]; + +extern word32 g_red_mask; +extern word32 g_green_mask; +extern word32 g_blue_mask; +extern int g_red_left_shift; +extern int g_green_left_shift; +extern int g_blue_left_shift; +extern int g_red_right_shift; +extern int g_green_right_shift; +extern int g_blue_right_shift; + +int g_use_shmem = 0; + +extern int Verbose; + +extern int g_warp_pointer; +extern int g_screen_depth; +extern int g_force_depth; +int g_screen_mdepth = 0; + +extern int g_send_sound_to_file; + +extern int g_quit_sim_now; +extern int g_config_control_panel; + +int g_auto_repeat_on = -1; +int g_x_shift_control_state = 0; + + +extern int Max_color_size; + +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; + +int g_alt_left_up = 1; +int g_alt_right_up = 1; + +extern word32 g_full_refresh_needed; + +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; + +extern int g_lores_colors[]; + +extern int g_a2vid_palette; + +extern int g_installed_full_superhires_colormap; + +extern int g_screen_redraw_skip_amt; + +extern word32 g_a2_screen_buffer_changed; +extern char *g_status_ptrs[MAX_STATUS_LINES]; +extern const char g_kegs_version_str[]; + +#if 0 +char g_printf_buf[4096]; +int g_debug_file_fd = -1; + +/* HACK to debug startup issues when launched from Finder */ +int +printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(g_printf_buf, 4090, fmt, ap); + + if(g_debug_file_fd < 0) { + g_debug_file_fd = open("/tmp/kegs.out", + O_CREAT | O_WRONLY | O_TRUNC, 0x1b6); + fprintf(stdout, "g_debug_file_fd = %d, %d\n", g_debug_file_fd, + errno); + } + write(1, g_printf_buf, strlen(g_printf_buf)); + write(g_debug_file_fd, g_printf_buf, strlen(g_printf_buf)); + + va_end(ap); + + return ret; +} +#endif + +pascal OSStatus +quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore) +{ + OSStatus err; + + err = CallNextEventHandler(call_ref, event); + if(err == noErr) { + g_quit_seen = 1; + } + return err; +} + +void +show_alert(const char *str1, const char *str2, const char *str3, int num) +{ + char buf[256]; + DialogRef alert; + DialogItemIndex out_item_hit; + CFStringRef cfstrref; + + if(num != 0) { + snprintf(buf, 250, "%s%s%s: %d", str1, str2, str3, num); + } else { + snprintf(buf, 250, "%s%s%s", str1, str2, str3); + } + + cfstrref = CFStringCreateWithCString(NULL, buf, + kCFStringEncodingMacRoman); + + CreateStandardAlert(kAlertStopAlert, cfstrref, CFSTR("Click OK"), + NULL, &alert); + RunStandardAlert(alert, NULL, &out_item_hit); +} + + + +pascal OSStatus +my_cmd_handler( EventHandlerCallRef handlerRef, EventRef event, void *userdata) +{ + OSStatus osresult; + HICommand command; + word32 command_id; + + osresult = eventNotHandledErr; + + GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, + sizeof(HICommand), NULL, &command); + + command_id = (word32)command.commandID; + switch(command_id) { + case 'Kbep': + SysBeep(10); + osresult = noErr; + break; + case 'abou': + show_alert("KEGSMAC v", g_kegs_version_str, + ", Copyright 2004 Kent Dickey\n" + "Latest version at http://kegs.sourceforge.net/\n", 0); + osresult = noErr; + break; + case 'KCFG': + g_config_control_panel = !g_config_control_panel; + osresult = noErr; + break; + case 'quit': + break; + case 'swin': + /* not sure what this is, but Panther sends it */ + break; + default: + printf("commandID %08x unknown\n", command_id); + SysBeep(90); + break; + } + return osresult; +} + +int g_upd_count = 0; + +void +update_window(void) +{ + SetPortWindowPort(g_main_window); + + PenNormal(); + + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + g_status_refresh_needed = 1; + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + + g_upd_count++; + if(g_upd_count > 250) { + g_upd_count = 0; + } + +} + +struct char_int_un { + union { + char c[4]; + UInt32 uint; + } u; + char c2[2]; +}; + +typedef struct char_int_un Char_int; + +int g_event_count = 0; + +void +show_event(UInt32 event_class, UInt32 event_kind, int handled) +{ + Char_int char_int; + + if(handled == 0 && event_class != 'cgs ') { + char_int.c2[0] = 0; + char_int.u.uint = event_class; + printf("Event %d: %08x = %s, %d\n", g_event_count, + (int)event_class, &(char_int.u.c[0]), (int)event_kind); + } + g_event_count++; +} + +pascal OSStatus +my_win_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata) +{ + OSStatus os_result; + UInt32 event_kind; + + os_result = eventNotHandledErr; + + // SysBeep(1); + + event_kind = GetEventKind(event); + // show_alert("win handler", event_kind); + if(event_kind == kEventWindowDrawContent) { + update_window(); + } if(event_kind == kEventWindowClose) { + g_quit_sim_now = 1; + g_quit_seen = 1; + my_exit(0); + } else { + show_event(GetEventClass(event), event_kind, 0); + update_window(); + } + + return os_result; +} + + +pascal OSStatus +dummy_event_handler(EventHandlerCallRef call_ref, EventRef in_event, + void *ignore) +{ + OSStatus err; + EventHandlerRef installed_handler; + EventTypeSpec event_spec = { kEventClassApplication, kEventAppQuit }; + + // From http://developer.apple.com/qa/qa2001/qa1061.html + // Trick to move main event queue to use ReceiveNextEvent in an event + // handler called by RunApplicationEventLoop + + err = InstallApplicationEventHandler(g_quit_handler_UPP, 1, &event_spec, + NULL, &installed_handler); + + kegsmain(g_mac_argc, g_mac_argv); + + return noErr; +} + +void +mac_update_modifiers(word32 state) +{ + word32 state_xor; + int is_up; + + state = state & (cmdKey | shiftKey | alphaLock | optionKey | + controlKey); + state_xor = g_mac_shift_control_state ^ state; + is_up = 0; + if(state_xor & controlKey) { + is_up = ((state & controlKey) == 0); + adb_physical_key_update(0x36, is_up); + } + if(state_xor & alphaLock) { + is_up = ((state & alphaLock) == 0); + adb_physical_key_update(0x39, is_up); + } + if(state_xor & shiftKey) { + is_up = ((state & shiftKey) == 0); + adb_physical_key_update(0x38, is_up); + } + if(state_xor & cmdKey) { + is_up = ((state & cmdKey) == 0); + adb_physical_key_update(0x37, is_up); + } + if(state_xor & optionKey) { + is_up = ((state & optionKey) == 0); + adb_physical_key_update(0x3a, is_up); + } + + g_mac_shift_control_state = state; +} + +void +mac_warp_mouse() +{ + Rect port_rect; + Point win_origin_pt; + CGPoint cgpoint; + CGDisplayErr cg_err; + + GetPortBounds(GetWindowPort(g_main_window), &port_rect); + SetPt(&win_origin_pt, port_rect.left, port_rect.top); + LocalToGlobal(&win_origin_pt); + + cgpoint = CGPointMake( (float)(win_origin_pt.h + X_A2_WINDOW_WIDTH/2), + (float)(win_origin_pt.v + X_A2_WINDOW_HEIGHT/2)); + cg_err = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); +} + +void +check_input_events() +{ + OSStatus err; + EventTargetRef target; + EventRef event; + UInt32 event_class, event_kind; + byte mac_keycode; + UInt32 keycode; + UInt32 modifiers; + Point mouse_point, mouse_delta_point; + WindowRef window_ref; + int button, button_state; + EventMouseButton mouse_button; + int handled; + int mouse_events; + int is_up; + int in_win; + int ignore; + + if(g_quit_seen) { + exit(0); + } + + SetPortWindowPort(g_main_window); + + mouse_events = 0; + target = GetEventDispatcherTarget(); + while(1) { + err = ReceiveNextEvent(0, NULL, kEventDurationNoWait, + true, &event); + + if(err == eventLoopTimedOutErr) { + break; + } + if(err != noErr) { + printf("err: %d\n", (int)err); + break; + } + + event_class = GetEventClass(event); + event_kind = GetEventKind(event); + handled = 0; + switch(event_class) { + case kEventClassKeyboard: + handled = 1; + keycode = 0; + modifiers = 0; + GetEventParameter(event, kEventParamKeyMacCharCodes, + typeChar, NULL, sizeof(byte), NULL, + &mac_keycode); + GetEventParameter(event, kEventParamKeyCode, + typeUInt32, NULL, sizeof(UInt32), NULL, + &keycode); + GetEventParameter(event, kEventParamKeyModifiers, + typeUInt32, NULL, sizeof(UInt32), NULL, + &modifiers); + + mac_update_modifiers((word32)modifiers); + + // Key up/down event + is_up = -1; + switch(event_kind) { + case kEventRawKeyDown: + is_up = 0; + //printf("key down: %02x, %08x\n", + // (int)mac_keycode, (int)keycode); + break; + case kEventRawKeyUp: + is_up = 1; + //printf("key up: %02x, %08x\n", + // (int)mac_keycode, (int)keycode); + break; + case kEventRawKeyModifiersChanged: + is_up = -1; + //printf("key xxx: %08x\n", (int)modifiers); + break; + } + if(is_up >= 0) { + adb_physical_key_update((int)keycode, is_up); + } + break; + case kEventClassMouse: + handled = 2; + mouse_events++; + GetEventParameter(event, kEventParamMouseLocation, + typeQDPoint, NULL, sizeof(Point), NULL, + &mouse_point); + GetWindowRegion(g_main_window, kWindowContentRgn, + g_event_rgnhandle); + in_win = PtInRgn(mouse_point, g_event_rgnhandle); + // in_win = 1 if it was in the contect region of window + err = GetEventParameter(event, kEventParamMouseDelta, + typeQDPoint, NULL, sizeof(Point), NULL, + &mouse_delta_point); + button = 0; + button_state = -1; + switch(event_kind) { + case kEventMouseDown: + button_state = 7; + handled = 3; + break; + case kEventMouseUp: + button_state = 0; + handled = 3; + break; + } + if(button_state >= 0) { + GetEventParameter(event, kEventParamMouseButton, + typeMouseButton, NULL, + sizeof(EventMouseButton), NULL, + &mouse_button); + button = mouse_button; + if(button > 1) { + button = 4 - button; + button = 1 << button; + } + ignore = (button_state != 0) && + (!in_win || g_ignore_next_click); + ignore = ignore || !g_mainwin_active; + if(ignore) { + // Outside of A2 window, ignore clicks + button = 0; + } + if(button_state == 0) { + g_ignore_next_click = 0; + } + } + + GlobalToLocal(&mouse_point); + + if(g_warp_pointer) { + if(err == 0) { + g_mac_mouse_x += mouse_delta_point.h; + g_mac_mouse_y += mouse_delta_point.v; + } + mac_warp_mouse(); + } else { + g_mac_mouse_x = mouse_point.h -BASE_MARGIN_LEFT; + g_mac_mouse_y = mouse_point.v -BASE_MARGIN_TOP; + } + +#if 0 + printf("Mouse %d at: %d,%d button:%d, button_st:%d\n", + mouse_events, g_mac_mouse_x, g_mac_mouse_y, + button, button_state); + printf("Mouse deltas: err:%d, %d,%d\n", (int)err, + mouse_delta_point.h, mouse_delta_point.v); +#endif + + update_mouse(g_mac_mouse_x, g_mac_mouse_y, + button_state, button & 7); + if(g_warp_pointer) { + g_mac_mouse_x = A2_WINDOW_WIDTH/2; + g_mac_mouse_y = A2_WINDOW_HEIGHT/2; + update_mouse(g_mac_mouse_x, g_mac_mouse_y,0,-1); + } + break; + case kEventClassApplication: + switch(event_kind) { + case kEventAppActivated: + handled = 1; + g_mainwin_active = 1; + window_ref = 0; + GetEventParameter(event, kEventParamWindowRef, + typeWindowRef, NULL, sizeof(WindowRef), + NULL, &window_ref); + if(window_ref == g_main_window) { + g_ignore_next_click = 1; + } + break; + case kEventAppDeactivated: + handled = 1; + g_mainwin_active = 0; + g_ignore_next_click = 1; + break; + } + break; + } + show_event(event_class, event_kind, handled); + if(handled != 1) { + (void)SendEventToEventTarget(event, target); + } + ReleaseEvent(event); + } + + return; +} + +void +temp_run_application_event_loop(void) +{ + OSStatus err; + EventRef dummy_event; + EventHandlerRef install_handler; + EventTypeSpec event_spec = { 'KWIN', 'KWIN' }; + + // Create UPP for dummy_event_handler and for quit_event_handler + err = noErr; + dummy_event = 0; + + g_dummy_event_handler_UPP = NewEventHandlerUPP(dummy_event_handler); + g_quit_handler_UPP = NewEventHandlerUPP(quit_event_handler); + if((g_dummy_event_handler_UPP == 0) || (g_quit_handler_UPP == 0)) { + err = memFullErr; + } + + if(err == noErr) { + err = InstallApplicationEventHandler(g_dummy_event_handler_UPP, + 1, &event_spec, 0, &install_handler); + if(err == noErr) { + err = MacCreateEvent(NULL, 'KWIN', 'KWIN', + GetCurrentEventTime(), kEventAttributeNone, + &dummy_event); + if(err == noErr) { + err = PostEventToQueue(GetMainEventQueue(), + dummy_event, kEventPriorityHigh); + } + if(err == noErr) { + RunApplicationEventLoop(); + } + + (void)RemoveEventHandler(install_handler); + } + } + + if(dummy_event != NULL) { + ReleaseEvent(dummy_event); + } +} + +int +main(int argc, char* argv[]) +{ + ProcessSerialNumber my_psn; + IBNibRef nibRef; + EventHandlerUPP handlerUPP; + EventTypeSpec cmd_event[3]; +#if 0 + MenuBarHandle mbar_handle; + MenuRef menu_ref; +#endif + Rect win_rect; + OSStatus err; + char *argptr; + int slash_cnt; + int i; + + /* Prepare argv0 */ + slash_cnt = 0; + argptr = argv[0]; + for(i = strlen(argptr); i >= 0; i--) { + if(argptr[i] == '/') { + slash_cnt++; + if(slash_cnt == 3) { + strncpy(&(g_argv0_path[0]), argptr, i); + g_argv0_path[i] = 0; + } + } + } + + printf("g_argv0_path is %s\n", g_argv0_path); + + g_mac_argv[0] = argv[0]; + g_mac_argc = 1; + i = 1; + while((i < argc) && (g_mac_argc < MAX_MAC_ARGS)) { + if(!strncmp(argv[i], "-psn", 4)) { + /* skip this argument */ + } else { + g_mac_argv[g_mac_argc++] = argv[i]; + } + i++; + } + + InitCursor(); + g_event_rgnhandle = NewRgn(); + g_status_font_family = FMGetFontFamilyFromName("\pCourier"); + SetRect(&win_rect, 0, 0, X_A2_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT + + MAX_STATUS_LINES*16 + 8); + OffsetRect(&win_rect, 64, 50); + + // Create a Nib reference passing the name of the nib file + // CreateNibReference only searches into the application bundle. + err = CreateNibReference(CFSTR("main"), &nibRef); + require_noerr( err, CantGetNibRef ); + + // Once the nib reference is created, set the menu bar. + err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar")); + require_noerr( err, CantSetMenuBar ); + + +#if 0 + mbar_handle = GetMenuBar(); + SetMenuBar(mbar_handle); + printf("mbar_handle: %p\n", mbar_handle); + + menu_ref = NewMenu(1, "\pTest"); + printf("menu_ref: %p\n", menu_ref); + AppendMenu(menu_ref, "\pTest item 1"); + InsertMenu(menu_ref, 0); +// ShowMenuBar(); // Don't call ShowMenuBar: it prevents menubar update! + DrawMenuBar(); + InvalMenuBar(); +#endif + + err = CreateNewWindow(kDocumentWindowClass, + kWindowStandardDocumentAttributes | + kWindowStandardHandlerAttribute, + &win_rect, &g_main_window); + + //printf("CreateNewWindow ret: %d, g_main_window: %p\n", (int)err, + // g_main_window); + + err = SetWindowTitleWithCFString(g_main_window, CFSTR("KEGSMAC")); + + // We don't need the nib reference anymore. + DisposeNibReference(nibRef); + + SysBeep(120); + + handlerUPP = NewEventHandlerUPP( my_cmd_handler ); + + cmd_event[0].eventClass = kEventClassCommand; + cmd_event[0].eventKind = kEventProcessCommand; + InstallWindowEventHandler(g_main_window, handlerUPP, 1, &cmd_event[0], + (void *)g_main_window, NULL); + + handlerUPP = NewEventHandlerUPP(my_win_handler); + cmd_event[0].eventClass = kEventClassWindow; + cmd_event[0].eventKind = kEventWindowDrawContent; + cmd_event[1].eventClass = kEventClassWindow; + cmd_event[1].eventKind = kEventWindowUpdate; + cmd_event[2].eventClass = kEventClassWindow; + cmd_event[2].eventKind = kEventWindowClose; + err = InstallWindowEventHandler(g_main_window, handlerUPP, 3, + &cmd_event[0], (void *)g_main_window, NULL); + require_noerr(err, CantCreateWindow); + + // Get screen depth + g_gdhandle = GetGDevice(); + g_screen_mdepth = (**((**g_gdhandle).gdPMap)).pixelSize; + + g_screen_depth = g_screen_mdepth; + + //printf("g_screen_depth = %d, depth: %d, bytes: %d\n", g_screen_depth, + // (**g_gdhandle).gdCCDepth, (**g_gdhandle).gdCCBytes); + + if(g_screen_depth > 16) { + /* 32-bit display */ + g_red_mask = 0xff; + g_green_mask = 0xff; + g_blue_mask = 0xff; + g_red_left_shift = 16; + g_green_left_shift = 8; + g_blue_left_shift = 0; + g_red_right_shift = 0; + g_green_right_shift = 0; + g_blue_right_shift = 0; + } else if(g_screen_depth > 8) { + /* 16-bit display */ + g_red_mask = 0x1f; + g_green_mask = 0x1f; + g_blue_mask = 0x1f; + g_red_left_shift = 10; + g_green_left_shift = 5; + g_blue_left_shift = 0; + g_red_right_shift = 3; + g_green_right_shift = 3; + g_blue_right_shift = 3; + } + + // show_alert("About to show window", (int)g_main_window); + update_window(); + + // The window was created hidden so show it. + ShowWindow( g_main_window ); + BringToFront( g_main_window ); + update_window(); + + // Make us pop to the front a different way + err = GetCurrentProcess(&my_psn); + if(err == noErr) { + (void)SetFrontProcess(&my_psn); + } + + // Call the event loop + temp_run_application_event_loop(); + +CantCreateWindow: +CantSetMenuBar: +CantGetNibRef: + show_alert("ending", "", "error code", err); + return err; +} + + +void +x_update_color(int col_num, int red, int green, int blue, word32 rgb) +{ +} + + +void +x_update_physical_colormap() +{ +} + +void +show_xcolor_array() +{ + int i; + + for(i = 0; i < 256; i++) { + printf("%02x: %08x\n", i, g_palette_8to1624[i]); + } +} + +void +xdriver_end() +{ + + printf("xdriver_end\n"); +} + +void +x_get_kimage(Kimage *kimage_ptr) +{ + PixMapHandle pixmap_handle; + GWorldPtr world; + Rect world_rect; + OSStatus err; + word32 *wptr; + byte *ptr; + int row_bytes; + int width; + int height; + int depth, mdepth; + int size; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + mdepth = kimage_ptr->mdepth; + + size = 0; + if(depth == g_screen_depth) { + SetRect(&world_rect, 0, 0, width, height); + err = NewGWorld( &world, 0, &world_rect, NULL, NULL, 0); + pixmap_handle = GetGWorldPixMap(world); + err = LockPixels(pixmap_handle); + ptr = (byte *)GetPixBaseAddr(pixmap_handle); + row_bytes = ((*pixmap_handle)->rowBytes & 0x3fff); + kimage_ptr->width_act = row_bytes / (mdepth >> 3); + mac_printf("Got depth: %d, bitmap_ptr: %p, width: %d\n", depth, + ptr, kimage_ptr->width_act); + mac_printf("pixmap->base: %08x, rowbytes: %08x, pixType:%08x\n", + (int)(*pixmap_handle)->baseAddr, + (*pixmap_handle)->rowBytes, + (*pixmap_handle)->pixelType); + wptr = (word32 *)(*pixmap_handle); + mac_printf("wptr: %p=%08x %08x %08x %08x %08x %08x %08x %08x\n", + wptr, + wptr[0], wptr[1], wptr[2], wptr[3], + wptr[4], wptr[5], wptr[6], wptr[7]); + kimage_ptr->dev_handle = pixmap_handle; + kimage_ptr->data_ptr = ptr; + } else { + + /* allocate buffers for video.c to draw into */ + + size = (width*height*mdepth) >> 3; + ptr = (byte *)malloc(size); + + if(ptr == 0) { + mac_printf("malloc for data fail, mdepth:%d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + kimage_ptr->dev_handle = (void *)-1; + } + + mac_printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr, + kimage_ptr->dev_handle, kimage_ptr->data_ptr, size); + +} + +void +dev_video_init() +{ + int lores_col; + int i; + + printf("Preparing graphics system\n"); + + video_get_kimages(); + + if(g_screen_depth != 8) { + // Get g_mainwin_kimage + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, + g_screen_mdepth); + } + + for(i = 0; i < 256; i++) { + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + + g_installed_full_superhires_colormap = 1; + + fflush(stdout); +} + + +void +x_redraw_status_lines() +{ + Rect rect; + Pattern white_pattern; + char tmp_buf[256]; + char *buf; + int len; + int line; + int height; + int margin; + + SetPortWindowPort(g_main_window); + PenNormal(); + height = 16; + margin = 0; + TextFont(g_status_font_family); + TextFace(normal); + TextSize(12); + + SetRect(&rect, 0, X_A2_WINDOW_HEIGHT + margin, X_A2_WINDOW_WIDTH, + X_A2_WINDOW_HEIGHT + margin + MAX_STATUS_LINES*height); + GetQDGlobalsWhite(&white_pattern); + FillRect(&rect, &white_pattern); + + for(line = 0; line < MAX_STATUS_LINES; line++) { + buf = g_status_ptrs[line]; + if(buf == 0) { + /* skip it */ + continue; + } + MoveTo(10, X_A2_WINDOW_HEIGHT + height*line + margin + height); + len = MIN(250, strlen(buf)); + strncpy(&tmp_buf[1], buf, len); + tmp_buf[0] = len; + DrawString(&tmp_buf[0]); + } + +} + + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, + int width, int height) +{ + PixMapHandle pixmap_handle; + Rect src_rect, dest_rect; + CGrafPtr window_port; + + SetPortWindowPort(g_main_window); + + pixmap_handle = kimage_ptr->dev_handle; + window_port = GetWindowPort(g_main_window); + SetRect(&src_rect, srcx, srcy, srcx + width, srcy + height); + SetRect(&dest_rect, destx, desty, destx + width, desty + height); + + CopyBits( (BitMap *)(*pixmap_handle), + GetPortBitMapForCopyBits(window_port), &src_rect, &dest_rect, + srcCopy, NULL); + +} + +void +x_push_done() +{ +} + +void +x_auto_repeat_on(int must) +{ +} + +void +x_auto_repeat_off(int must) +{ +} + +void +x_hide_pointer(int do_hide) +{ + if(do_hide) { + HideCursor(); + } else { + ShowCursor(); + } +} diff --git a/src/macsnd_driver.c b/src/macsnd_driver.c new file mode 100644 index 0000000..a869d3f --- /dev/null +++ b/src/macsnd_driver.c @@ -0,0 +1,154 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_macsnd_driver_c[] = "@(#)$KmKId: macsnd_driver.c,v 1.4 2003-10-17 15:57:40-04 kentd Exp $"; + +#include "defc.h" +#include "sound.h" + +#include +#include + +#define MACSND_REBUF_SIZE (64*1024) +#define MACSND_QUANTA 512 +/* MACSND_QUANTA must be >= 128 and a power of 2 */ + +word32 g_macsnd_rebuf[MACSND_REBUF_SIZE]; +volatile word32 *g_macsnd_rebuf_ptr; +volatile word32 *g_macsnd_rebuf_cur; +volatile int g_macsnd_playing = 0; + +extern int Verbose; + +extern int g_audio_rate; +extern word32 *g_sound_shm_addr; +extern int g_sound_size; + + +SndChannelPtr g_snd_channel_ptr; +ExtSoundHeader g_snd_hdr; +SndCommand g_snd_cmd; + +void +mac_snd_callback(SndChannelPtr snd_chan_ptr, SndCommand *in_sndcmd) +{ + OSStatus err; + int samps; + + // This is an interrupt routine--no printf, etc! + + samps = g_macsnd_rebuf_ptr - g_macsnd_rebuf_cur; + if(samps < 0) { + samps += MACSND_REBUF_SIZE; + } + + samps = samps & -(MACSND_QUANTA); // quantize to 1024 samples + if(g_macsnd_rebuf_cur + samps > &(g_macsnd_rebuf[MACSND_REBUF_SIZE])) { + samps = &(g_macsnd_rebuf[MACSND_REBUF_SIZE]) - + g_macsnd_rebuf_cur; + } + if(samps > 0) { + g_macsnd_playing = 1; + g_snd_hdr.numFrames = samps; + g_snd_hdr.loopEnd = samps; + g_snd_hdr.samplePtr = (byte *)g_macsnd_rebuf_cur; + + g_snd_cmd.cmd = bufferCmd; + g_snd_cmd.param1 = 0; + g_snd_cmd.param2 = (long) &g_snd_hdr; + + g_macsnd_rebuf_cur += samps; + if(g_macsnd_rebuf_cur >= &(g_macsnd_rebuf[MACSND_REBUF_SIZE])) { + g_macsnd_rebuf_cur -= MACSND_REBUF_SIZE; + } + + err = SndDoImmediate(g_snd_channel_ptr, &g_snd_cmd); + + // And set-up callback + g_snd_cmd.cmd = callBackCmd; + g_snd_cmd.param1 = 0; + g_snd_cmd.param2 = 0; + err = SndDoCommand(g_snd_channel_ptr, &g_snd_cmd, TRUE); + } else { + g_macsnd_playing = 0; + } +} + +int +mac_send_audio(byte *ptr, int in_size) +{ + SndCommand snd_cmd = {0}; + word32 *wptr, *macptr; + word32 *eptr; + int samps; + int i; + + samps = in_size / 4; + wptr = (word32 *)ptr; + macptr = (word32 *)g_macsnd_rebuf_ptr; + eptr = &g_macsnd_rebuf[MACSND_REBUF_SIZE]; + for(i = 0; i < samps; i++) { + *macptr++ = *wptr++; + if(macptr >= eptr) { + macptr = &g_macsnd_rebuf[0]; + } + } + + g_macsnd_rebuf_ptr = macptr; + + if(!g_macsnd_playing) { + mac_snd_callback(g_snd_channel_ptr, &snd_cmd); + } + + return in_size; +} + +void +child_sound_init_mac() +{ + OSStatus err; + + mac_printf("In mac child\n"); + fflush(stdout); + mac_printf("pid: %d\n", getpid()); + fflush(stdout); + + //return; + + //g_snd_channel_ptr = 0; + err = SndNewChannel(&g_snd_channel_ptr, sampledSynth, initStereo, + NewSndCallBackUPP(mac_snd_callback)); + mac_printf("SndNewChannel ret: %d\n", (int)err); + fflush(stdout); + + memset(&g_snd_hdr, 0, sizeof(g_snd_hdr)); + g_snd_hdr.sampleSize = 16; + g_snd_hdr.numChannels = 2; + g_audio_rate = 44100; + g_snd_hdr.sampleRate = g_audio_rate << 16; + g_snd_hdr.numFrames = 0; // will be set in mac_send_audio + g_snd_hdr.encode = extSH; + g_snd_hdr.baseFrequency = 0; + g_snd_hdr.samplePtr = 0; + + set_audio_rate(g_audio_rate); + + mac_printf("End of child_sound_init_mac\n"); + fflush(stdout); +} + +void +macsnd_init(word32 *shmaddr) +{ + g_macsnd_rebuf_cur = &g_macsnd_rebuf[0]; + g_macsnd_rebuf_ptr = &g_macsnd_rebuf[0]; + mac_printf("macsnd_init called\n"); + child_sound_loop(-1, -1, shmaddr); +} diff --git a/src/make_inst b/src/make_inst new file mode 100755 index 0000000..b84f665 --- /dev/null +++ b/src/make_inst @@ -0,0 +1,31 @@ +#!/usr/local/bin/perl -w + +# $KmKId: make_inst,v 1.5 2002-11-07 08:18:16-08 kadickey Exp $ + +$is_c = shift; +$repl = shift; + +$count = 0; + +while(<>) { + $line = $_; + if(/^inst(..)_SYM(.*)$/) { + if($is_c eq "c") { + if($count > 0) { + printf("\tbreak;\n"); + } + print "case 0x$1: $2\n"; + $count++; + } else { + print "\t.align\t8\n"; + print "inst" . "$1" . "_$repl" . "$2\n"; + } + } elsif(/^(.*)_SYM(.*)$/) { + print "$1" . "_$repl" . "$2\n"; + } else { + print $line; + } +} +# if(/^inst(..)_SYM (.*)$/) { +# print "OPCODE($1) /* $2 */\n"; +# } else if(/^( diff --git a/src/make_size b/src/make_size new file mode 100755 index 0000000..12f4066 --- /dev/null +++ b/src/make_size @@ -0,0 +1,30 @@ +#!/usr/local/bin/perl -w +# $KmKId: make_size,v 1.3 2002-11-07 08:18:16-08 kadickey Exp $ + +$repl = shift; + +while(<>) { + $line = $_; + if(/\.word inst(..)_SYM\+(.)(.*)$/) { + if($repl eq "c") { + print "\t0x$2, /* $1 */ $3\n"; + } elsif($repl eq "s") { + print "\t.byte 0x$2, /* $1 */ $3\n"; + } else { + print "\t.word\tinst$1" . "_$repl" . "\t/*$2*/ $3\n"; + } + } elsif (/\.block.*$/) { + if($repl eq "c") { + print "\n"; + } elsif($repl eq "s") { + print "\n"; + } else { + print $line; + } + } else { + print $line; + } +} +# if(/^inst(..)_SYM (.*)$/) { +# print "OPCODE($1) /* $2 */\n"; +# } else if(/^( diff --git a/src/make_win b/src/make_win new file mode 100755 index 0000000..092ec31 --- /dev/null +++ b/src/make_win @@ -0,0 +1,4 @@ +#!/bin/sh + +export PATH="/mingw/bin:${PATH}" +make diff --git a/src/moremem.c b/src/moremem.c new file mode 100644 index 0000000..30425e7 --- /dev/null +++ b/src/moremem.c @@ -0,0 +1,2353 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_moremem_c[] = "@(#)$KmKId: moremem.c,v 1.233 2004-03-23 17:27:14-05 kentd Exp $"; + +#include "defc.h" + +extern int daylight; + +extern char g_kegs_version_str[]; + +extern byte *g_memory_ptr; +extern byte *g_dummy_memory1_ptr; +extern byte *g_slow_memory_ptr; +extern byte *g_rom_fc_ff_ptr; +extern byte *g_rom_cards_ptr; +extern word32 g_mem_size_total; + +extern word32 slow_mem_changed[]; + +extern int g_num_breakpoints; +extern word32 g_breakpts[]; + +extern int halt_sim; +extern double g_last_vbl_dcycs; + +extern Page_info page_info_rd_wr[]; + +extern int scr_mode; + +extern int Verbose; +extern int Halt_on; +extern double g_paddle_trig_dcycs; +extern int g_rom_version; + +extern int g_paddle_button[4]; + +extern Fplus *g_cur_fplus_ptr; + +/* from iwm.c */ +extern int head_35; +extern int g_apple35_sel; +extern int cur_drive; + +int g_zipgs_unlock = 0; +int g_zipgs_reg_c059 = 0x5f; + // 7=LC cache dis, 6==5ms paddle del en, 5==5ms ext del en, + // 4==5ms c02e enab, 3==CPS follow enab, 2-0: 111 +int g_zipgs_reg_c05a = 0x0f; + // 7:4 = current ZIP speed, 0=100%, 1=93.75%, F=6.25% + // 3:0: always 1111 +int g_zipgs_reg_c05b = 0x40; + // 7==1ms clock, 6==cshupd: tag data at c05f updated + // 5==LC cache disable, 4==bd is disabled, 3==delay in effect, + // 2==rombank, 1-0==ram size (00:8K, 01=16K, 10=32K, 11=64K) +int g_zipgs_reg_c05c = 0x00; + // 7:1==slot delay enable (for 52-54ms), 0==speaker 5ms delay + +int g_emubyte_cnt = 0; + +int statereg; +int halt_on_c02a = 0; +int g_shadow_all_banks = 0; +int g_num_shadow_all_banks = 0; + +extern Engine_reg engine; + +#define IOR(val) ( (val) ? 0x80 : 0x00 ) + +int linear_vid = 1; +int bank1latch = 0; + +int wrdefram = 0; +int int_crom[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +extern int g_cur_a2_stat; + +int annunc_0 = 0; +int annunc_1 = 0; +int annunc_2 = 0; + +int shadow_reg = 0x08; + +int stop_on_c03x = 0; + +extern int doc_ptr; + +int shadow_text = 1; + +int g_border_color = 0; + +int speed_fast = 1; +word32 g_slot_motor_detect = 0; +int power_on_clear = 0; + + +int g_c023_val = 0; +int c023_scan_int_irq_pending = 0; +int c023_1sec_int_irq_pending = 0; + +int c02b_val = 0x08; + +int c039_write_val = 0; + +int c041_en_25sec_ints = 0; +int c041_en_vbl_ints = 0; +int c041_en_switch_ints = 0; +int c041_en_move_ints = 0; +int c041_en_mouse = 0; + +int g_c046_val = 0; + +int c046_25sec_irq_pend = 0; +int c046_vbl_irq_pending = 0; + + +#define UNIMPL_READ \ + halt_printf("UNIMP READ to addr %08x\n", loc); \ + return 0; + +#define UNIMPL_WRITE \ + halt_printf("UNIMP WRITE to addr %08x, val: %04x\n", loc, val); \ + return; + +void +fixup_brks() +{ + word32 page; + word32 tmp, tmp2; + Pg_info val; + int i, num; + + num = g_num_breakpoints; + for(i = 0; i < num; i++) { + page = (g_breakpts[i] >> 8) & 0xffff; + val = GET_PAGE_INFO_RD(page); + tmp = PTR2WORD(val) & 0xff; + tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; + SET_PAGE_INFO_RD(page, val - tmp + tmp2); + val = GET_PAGE_INFO_WR(page); + tmp = PTR2WORD(val) & 0xff; + tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; + SET_PAGE_INFO_WR(page, val - tmp + tmp2); + } +} + +void +fixup_hires_on() +{ + if((g_cur_a2_stat & ALL_STAT_ST80) == 0) { + return; + } + + fixup_bank0_2000_4000(); + fixup_brks(); +} + +void +fixup_bank0_2000_4000() +{ + byte *mem0rd; + byte *mem0wr; + + mem0rd = &(g_memory_ptr[0x2000]); + mem0wr = mem0rd; + if((g_cur_a2_stat & ALL_STAT_ST80) && (g_cur_a2_stat & ALL_STAT_HIRES)){ + if(PAGE2) { + mem0rd += 0x10000; + mem0wr += 0x10000; + if((shadow_reg & 0x12) == 0 || (shadow_reg & 0x8) == 0){ + mem0wr += BANK_SHADOW2; + } + } else if((shadow_reg & 0x02) == 0) { + mem0wr += BANK_SHADOW; + } + + } else { + if(RAMRD) { + mem0rd += 0x10000; + } + if(RAMWRT) { + mem0wr += 0x10000; + if((shadow_reg & 0x12) == 0 || (shadow_reg & 0x8) == 0){ + mem0wr += BANK_SHADOW2; + } + } else if((shadow_reg & 0x02) == 0) { + mem0wr += BANK_SHADOW; + } + } + + fixup_any_bank_any_page(0x20, 0x20, mem0rd, mem0wr); +} + +void +fixup_bank0_0400_0800() +{ + byte *mem0rd; + byte *mem0wr; + int shadow; + + mem0rd = &(g_memory_ptr[0x400]); + mem0wr = mem0rd; + shadow = BANK_SHADOW; + if(g_cur_a2_stat & ALL_STAT_ST80) { + if(PAGE2) { + shadow = BANK_SHADOW2; + mem0rd += 0x10000; + mem0wr += 0x10000; + } + } else { + if(RAMWRT) { + shadow = BANK_SHADOW2; + mem0wr += 0x10000; + } + if(RAMRD) { + mem0rd += 0x10000; + } + } + if((shadow_reg & 0x01) == 0) { + mem0wr += shadow; + } + + fixup_any_bank_any_page(0x4, 4, mem0rd, mem0wr); +} + +void +fixup_any_bank_any_page(int start_page, int num_pages, byte *mem0rd, + byte *mem0wr) +{ + int i; + + for(i = 0; i < num_pages; i++) { + SET_PAGE_INFO_RD(i + start_page, mem0rd); + mem0rd += 0x100; + } + + for(i = 0; i < num_pages; i++) { + SET_PAGE_INFO_WR(i + start_page, mem0wr); + mem0wr += 0x100; + } + +} + +void +fixup_intcx() +{ + byte *rom10000; + byte *rom_inc; + int no_io_shadow; + int off; + int start_k; + int indx; + int j, k; + + rom10000 = &(g_rom_fc_ff_ptr[0x30000]); + + no_io_shadow = (shadow_reg & 0x40); + + start_k = 0; + if(no_io_shadow) { + /* if not shadowing, banks 0 and 1 are not affected by intcx */ + start_k = 2; + } + + for(k = start_k; k < 4; k++) { + off = k; + if(k >= 2) { + off += (0xe0 - 2); + } + /* step off through 0x00, 0x01, 0xe0, 0xe1 */ + + off = off << 8; + SET_PAGE_INFO_RD(0xc0 + off, SET_BANK_IO); + + for(j = 0xc1; j < 0xc8; j++) { + indx = j & 0xf; + if(j < 0xc8) { + rom_inc = SET_BANK_IO; + if((int_crom[indx] == 0) || INTCX) { + rom_inc = rom10000 + (j << 8); + } else { + // User-slot rom + rom_inc = &(g_rom_cards_ptr[0]) + + ((j - 0xc0) << 8); + } + SET_PAGE_INFO_RD(j + off, rom_inc); + } + } + for(j = 0xc8; j < 0xd0; j++) { + /* c800 - cfff */ + if(int_crom[3] == 0 || INTCX) { + rom_inc = rom10000 + (j << 8); + } else { + /* c800 space not necessarily mapped */ + /* just map in ROM */ + rom_inc = rom10000 + (j << 8); + } + SET_PAGE_INFO_RD(j + off, rom_inc); + } + for(j = 0xc0; j < 0xd0; j++) { + SET_PAGE_INFO_WR(j + off, SET_BANK_IO); + } + } + + if(!no_io_shadow) { + SET_PAGE_INFO_RD(0xc7, SET_BANK_IO); /* smartport */ + } + + fixup_brks(); +} + +void +fixup_wrdefram(int new_wrdefram) +{ + byte *mem0wr; + byte *wrptr; + int j; + + wrdefram = new_wrdefram; + + if(shadow_reg & 0x40) { + /* do nothing */ + return; + } + + /* if shadowing, banks 0 and 1 are affected by wrdefram */ + mem0wr = &(g_memory_ptr[0]); + if(!new_wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + + wrptr = mem0wr + 0x1e000; + for(j = 0x1e0; j < 0x200; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } + + wrptr = mem0wr + 0x0e000; + if(ALTZP) { + wrptr += 0x10000; + } + for(j = 0xe0; j < 0x100; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } + + wrptr = mem0wr + 0x1d000; + if(! LCBANK2) { + wrptr -= 0x1000; + } + for(j = 0x1d0; j < 0x1e0; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } + + wrptr = mem0wr + 0xd000; + if(! LCBANK2) { + wrptr -= 0x1000; + } + if(ALTZP) { + wrptr += 0x10000; + } + for(j = 0xd0; j < 0xe0; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } + + fixup_brks(); +} + +void +fixup_st80col(double dcycs) +{ + int cur_a2_stat; + + cur_a2_stat = g_cur_a2_stat; + + fixup_bank0_0400_0800(); + + if(cur_a2_stat & ALL_STAT_HIRES) { + /* fixup no matter what PAGE2 since PAGE2 and RAMRD/WR */ + /* can work against each other */ + fixup_bank0_2000_4000(); + } + + if(PAGE2) { + change_display_mode(dcycs); + } + + fixup_brks(); +} + +void +fixup_altzp() +{ + byte *mem0rd, *mem0wr; + int altzp; + + altzp = ALTZP; + mem0rd = &(g_memory_ptr[0]); + if(altzp) { + mem0rd += 0x10000; + } + SET_PAGE_INFO_RD(0, mem0rd); + SET_PAGE_INFO_RD(1, mem0rd + 0x100); + SET_PAGE_INFO_WR(0, mem0rd); + SET_PAGE_INFO_WR(1, mem0rd + 0x100); + + mem0rd = &(g_memory_ptr[0xd000]); + mem0wr = mem0rd; + + if(shadow_reg & 0x40) { + if(ALTZP) { + mem0rd += 0x10000; + } + fixup_any_bank_any_page(0xd0, 0x10, mem0rd - 0x1000, + mem0rd - 0x1000); + } else { + if(!wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if(ALTZP) { + mem0rd += 0x10000; + mem0wr += 0x10000; + } + if(! LCBANK2) { + mem0rd -= 0x1000; + mem0wr -= 0x1000; + } + if(RDROM) { + mem0rd = &(g_rom_fc_ff_ptr[0x3d000]); + } + fixup_any_bank_any_page(0xd0, 0x10, mem0rd, mem0wr); + } + + mem0rd = &(g_memory_ptr[0xe000]); + mem0wr = mem0rd; + if(!wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if(ALTZP) { + mem0rd += 0x10000; + mem0wr += 0x10000; + } + if(RDROM) { + mem0rd = &(g_rom_fc_ff_ptr[0x3e000]); + } + fixup_any_bank_any_page(0xe0, 0x20, mem0rd, mem0wr); +} + +void +fixup_page2(double dcycs) +{ + if((g_cur_a2_stat & ALL_STAT_ST80)) { + fixup_bank0_0400_0800(); + if((g_cur_a2_stat & ALL_STAT_HIRES)) { + fixup_bank0_2000_4000(); + } + } else { + change_display_mode(dcycs); + } +} + +void +fixup_ramrd() +{ + byte *mem0rd; + int cur_a2_stat; + int j; + + cur_a2_stat = g_cur_a2_stat; + + if((cur_a2_stat & ALL_STAT_ST80) == 0) { + fixup_bank0_0400_0800(); + } + if( ((cur_a2_stat & ALL_STAT_ST80) == 0) || + ((cur_a2_stat & ALL_STAT_HIRES) == 0) ) { + fixup_bank0_2000_4000(); + } + + mem0rd = &(g_memory_ptr[0x0000]); + if(RAMRD) { + mem0rd += 0x10000; + } + + SET_PAGE_INFO_RD(2, mem0rd + 0x200); + SET_PAGE_INFO_RD(3, mem0rd + 0x300); + + for(j = 8; j < 0x20; j++) { + SET_PAGE_INFO_RD(j, mem0rd + j*0x100); + } + + for(j = 0x40; j < 0xc0; j++) { + SET_PAGE_INFO_RD(j, mem0rd + j*0x100); + } +} + +void +fixup_ramwrt() +{ + byte *mem0wr; + int cur_a2_stat; + int shadow; + int ramwrt; + int j; + + cur_a2_stat = g_cur_a2_stat; + + if((cur_a2_stat & ALL_STAT_ST80) == 0) { + fixup_bank0_0400_0800(); + } + if( ((cur_a2_stat & ALL_STAT_ST80) == 0) || + ((cur_a2_stat & ALL_STAT_HIRES) == 0) ) { + fixup_bank0_2000_4000(); + } + + mem0wr = &(g_memory_ptr[0x0000]); + ramwrt = RAMWRT; + if(ramwrt) { + mem0wr += 0x10000; + } + + SET_PAGE_INFO_WR(2, mem0wr + 0x200); + SET_PAGE_INFO_WR(3, mem0wr + 0x300); + + shadow = BANK_SHADOW; + if(ramwrt) { + shadow = BANK_SHADOW2; + } + if(((shadow_reg & 0x20) != 0) || g_rom_version < 3) { + shadow = 0; + } + for(j = 8; j < 0x0c; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); + } + + for(j = 0xc; j < 0x20; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } + + shadow = 0; + if(ramwrt) { + if((shadow_reg & 0x14) == 0 || (shadow_reg & 0x08) == 0) { + shadow = BANK_SHADOW2; + } + } else if((shadow_reg & 0x04) == 0) { + shadow = BANK_SHADOW; + } + for(j = 0x40; j < 0x60; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); + } + + shadow = 0; + if(ramwrt && (shadow_reg & 0x08) == 0) { + /* shr shadowing */ + shadow = BANK_SHADOW2; + } + for(j = 0x60; j < 0xa0; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); + } + + for(j = 0xa0; j < 0xc0; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } +} + +void +fixup_lcbank2() +{ + byte *mem0rd, *mem0wr; + int off; + int k; + + for(k = 0; k < 4; k++) { + off = k; + if(k >= 2) { + off += (0xe0 - 2); + } + /* step off through 0x00, 0x01, 0xe0, 0xe1 */ + + if(k < 2) { + mem0rd = &(g_memory_ptr[k << 16]); + } else { + mem0rd = &(g_slow_memory_ptr[(k & 1) << 16]); + } + if((k == 0) && ALTZP) { + mem0rd += 0x10000; + } + if(! LCBANK2) { + mem0rd -= 0x1000; /* lcbank1, use 0xc000-cfff */ + } + mem0wr = mem0rd; + if((k < 2) && !wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if((k < 2) && RDROM) { + mem0rd = &(g_rom_fc_ff_ptr[0x30000]); + } + fixup_any_bank_any_page(off*0x100 + 0xd0, 0x10, + mem0rd + 0xd000, mem0wr + 0xd000); + } +} + +void +fixup_rdrom() +{ + byte *mem0rd; + int j, k; + + /* fixup_lcbank2 handles 0xd000-dfff for rd & wr*/ + fixup_lcbank2(); + + for(k = 0; k < 2; k++) { + /* k is the bank */ + mem0rd = &(g_memory_ptr[k << 16]); + if((k == 0) && ALTZP) { + mem0rd += 0x10000; + } + if((shadow_reg & 0x40) == 0) { + if(RDROM) { + mem0rd = &(g_rom_fc_ff_ptr[0x30000]); + } + } + for(j = 0xe0; j < 0x100; j++) { + SET_PAGE_INFO_RD(j + k*0x100, mem0rd + j*0x100); + } + } + +} + +void +set_statereg(double dcycs, int val) +{ + int xor; + + xor = val ^ statereg; + statereg = val; + if(xor == 0) { + return; + } + + if(xor & 0x80) { + /* altzp */ + fixup_altzp(); + } + if(xor & 0x40) { + /* page2 */ + fixup_page2(dcycs); + } + + if(xor & 0x20) { + /* RAMRD */ + fixup_ramrd(); + } + + if(xor & 0x10) { + /* RAMWRT */ + fixup_ramwrt(); + } + + if(xor & 0x08) { + /* RDROM */ + fixup_rdrom(); + } + + if(xor & 0x04) { + /* LCBANK2 */ + fixup_lcbank2(); + } + + if(xor & 0x02) { + /* ROMBANK */ + halt_printf("Just set rombank = %d\n", ROMB); + } + + if(xor & 0x01) { + fixup_intcx(); + } + + if(xor) { + fixup_brks(); + } +} + +void +fixup_shadow_txt1() +{ + byte *mem0wr; + int j; + + fixup_bank0_0400_0800(); + + mem0wr = &(g_memory_ptr[0x10000]); + if((shadow_reg & 0x01) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 4; j < 8; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } +} + +void +fixup_shadow_txt2() +{ + byte *mem0wr; + int shadow; + int j; + + /* bank 0 */ + mem0wr = &(g_memory_ptr[0x00000]); + shadow = BANK_SHADOW; + if(RAMWRT) { + mem0wr += 0x10000; + shadow = BANK_SHADOW2; + } + if(((shadow_reg & 0x20) == 0) && (g_rom_version >= 3)) { + mem0wr += shadow; + } + for(j = 8; j < 0xc; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } + + /* and bank 1 */ + mem0wr = &(g_memory_ptr[0x10000]); + if(((shadow_reg & 0x20) == 0) && (g_rom_version >= 3)) { + mem0wr += BANK_SHADOW2; + } + for(j = 8; j < 0xc; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } +} + +void +fixup_shadow_hires1() +{ + byte *mem0wr; + int j; + + fixup_bank0_2000_4000(); + + /* and bank 1 */ + mem0wr = &(g_memory_ptr[0x10000]); + if((shadow_reg & 0x12) == 0 || (shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 0x20; j < 0x40; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } +} + +void +fixup_shadow_hires2() +{ + byte *mem0wr; + int j; + + /* bank 0 */ + mem0wr = &(g_memory_ptr[0x00000]); + if(RAMWRT) { + mem0wr += 0x10000; + if((shadow_reg & 0x14) == 0 || (shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + } else if((shadow_reg & 0x04) == 0) { + mem0wr += BANK_SHADOW; + } + for(j = 0x40; j < 0x60; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } + + /* and bank 1 */ + mem0wr = &(g_memory_ptr[0x10000]); + if((shadow_reg & 0x14) == 0 || (shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 0x40; j < 0x60; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } +} + +void +fixup_shadow_shr() +{ + byte *mem0wr; + int j; + + /* bank 0, only pages 0x60 - 0xa0 */ + mem0wr = &(g_memory_ptr[0x00000]); + if(RAMWRT) { + mem0wr += 0x10000; + if((shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + } + for(j = 0x60; j < 0xa0; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } + + /* and bank 1, only pages 0x60 - 0xa0 */ + mem0wr = &(g_memory_ptr[0x10000]); + if((shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 0x60; j < 0xa0; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } +} + +void +fixup_shadow_iolc() +{ + byte *mem0rd, *mem0wr; + int k; + + for(k = 0; k < 2; k++) { + mem0rd = &(g_memory_ptr[k << 16]); + if(shadow_reg & 0x40) { + fixup_any_bank_any_page((k << 8) + 0xc0, 0x10, + mem0rd + 0xd000, mem0rd + 0xd000); + if(k == 0 && ALTZP) { + mem0rd += 0x10000; + } + fixup_any_bank_any_page((k << 8) + 0xd0, 0x10, + mem0rd + 0xc000, mem0rd + 0xc000); + fixup_any_bank_any_page((k << 8) + 0xe0, 0x20, + mem0rd + 0xe000, mem0rd + 0xe000); + } else { + /* 0xc000 area */ + fixup_intcx(); + + /* 0xd000 area */ + fixup_lcbank2(); + + if(k == 0 && ALTZP) { + mem0rd += 0x10000; + } + mem0wr = mem0rd; + if(!wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if(RDROM) { + mem0rd = &(g_rom_fc_ff_ptr[0x30000]); + } + fixup_any_bank_any_page((k << 8) + 0xe0, 0x20, + mem0rd + 0xe000, mem0wr + 0xe000); + } + } +} + +void +update_shadow_reg(int val) +{ + int xor; + + if(shadow_reg == val) { + return; + } + + xor = shadow_reg ^ val; + shadow_reg = val; + + if(xor & 8) { + fixup_shadow_hires1(); + fixup_shadow_hires2(); + fixup_shadow_shr(); + xor = xor & (~0x16); + } + if(xor & 0x10) { + fixup_shadow_hires1(); + fixup_shadow_hires2(); + xor = xor & (~0x6); + } + if(xor & 2) { + fixup_shadow_hires1(); + } + if(xor & 4) { + fixup_shadow_hires2(); + } + if(xor & 1) { + fixup_shadow_txt1(); + } + if((xor & 0x20) && g_rom_version >= 3) { + fixup_shadow_txt2(); + } + if(xor & 0x40) { + fixup_shadow_iolc(); + } +} + +void +fixup_shadow_all_banks() +{ + byte *mem0rd; + int shadow; + int num_banks; + int j, k; + + /* Assume Ninja Force Megademo */ + /* only do banks 3 - num_banks by 2, shadowing into e1 */ + + shadow = 0; + if(g_shadow_all_banks && ((shadow_reg & 0x08) == 0)) { + shadow = BANK_SHADOW2; + } + num_banks = g_mem_size_total >> 16; + for(k = 3; k < num_banks; k += 2) { + mem0rd = &(g_memory_ptr[k*0x10000 + 0x2000]) + shadow; + for(j = 0x20; j < 0xa0; j++) { + SET_PAGE_INFO_WR(k*0x100 + j, mem0rd); + mem0rd += 0x100; + } + } +} + +void +setup_pageinfo() +{ + byte *mem0rd; + word32 mem_size_pages; + + /* first, set all of memory to point to itself */ + + mem_size_pages = g_mem_size_total >> 8; + mem0rd = &(g_memory_ptr[0]); + fixup_any_bank_any_page(0, mem_size_pages, mem0rd, mem0rd); + + /* mark unused memory as BAD_MEM */ + fixup_any_bank_any_page(mem_size_pages, 0xfc00-mem_size_pages, + BANK_BAD_MEM, BANK_BAD_MEM); + + fixup_shadow_all_banks(); + + /* ROM */ + mem0rd = &(g_rom_fc_ff_ptr[0]); + fixup_any_bank_any_page(0xfc00, 0x400, mem0rd, + mem0rd + (BANK_IO_TMP | BANK_IO2_TMP)); + + /* banks e0, e1 */ + mem0rd = &(g_slow_memory_ptr[0]); + fixup_any_bank_any_page(0xe000, 0x04, mem0rd + 0x0000, mem0rd + 0x0000); + fixup_any_bank_any_page(0xe004, 0x08, mem0rd + 0x0400, + mem0rd + 0x0400 + BANK_SHADOW); + fixup_any_bank_any_page(0xe00c, 0x14, mem0rd + 0x0c00, mem0rd + 0x0c00); + fixup_any_bank_any_page(0xe020, 0x40, mem0rd + 0x2000, + mem0rd + 0x2000 + BANK_SHADOW); + fixup_any_bank_any_page(0xe060, 0xa0, mem0rd + 0x6000, mem0rd + 0x6000); + + mem0rd = &(g_slow_memory_ptr[0x10000]); + fixup_any_bank_any_page(0xe100, 0x04, mem0rd + 0x0000, mem0rd + 0x0000); + fixup_any_bank_any_page(0xe104, 0x08, mem0rd + 0x0400, + mem0rd + 0x0400 + BANK_SHADOW2); + fixup_any_bank_any_page(0xe10c, 0x14, mem0rd + 0x0c00, mem0rd + 0x0c00); + fixup_any_bank_any_page(0xe120, 0x80, mem0rd + 0x2000, + mem0rd + 0x2000 + BANK_SHADOW2); + fixup_any_bank_any_page(0xe1a0, 0x60, mem0rd + 0xa000, mem0rd + 0xa000); + + fixup_intcx(); /* correct banks 0xe0,0xe1, 0xc000-0xcfff area */ + fixup_lcbank2(); /* correct 0xd000-0xdfff area */ + + fixup_bank0_2000_4000(); + fixup_bank0_0400_0800(); + fixup_wrdefram(wrdefram); + fixup_altzp(); + fixup_ramrd(); + fixup_ramwrt(); + fixup_rdrom(); + fixup_shadow_txt1(); + fixup_shadow_txt2(); + fixup_shadow_hires1(); + fixup_shadow_hires2(); + fixup_shadow_shr(); + fixup_shadow_iolc(); + fixup_brks(); +} + +void +show_bankptrs_bank0rdwr() +{ + show_bankptrs(0); + show_bankptrs(1); + show_bankptrs(0xe0); + show_bankptrs(0xe1); + printf("statereg: %02x\n", statereg); +} + +void +show_bankptrs(int bnk) +{ + int i; + Pg_info rd, wr; + byte *ptr_rd, *ptr_wr; + + printf("g_memory_ptr: %p, dummy_mem: %p, slow_mem_ptr: %p\n", + g_memory_ptr, g_dummy_memory1_ptr, g_slow_memory_ptr); + printf("g_rom_fc_ff_ptr: %p\n", g_rom_fc_ff_ptr); + + printf("Showing bank_info array for %02x\n", bnk); + for(i = 0; i < 256; i++) { + rd = GET_PAGE_INFO_RD(bnk*0x100 + i); + wr = GET_PAGE_INFO_WR(bnk*0x100 + i); + ptr_rd = (byte *)rd; + ptr_wr = (byte *)wr; + printf("%04x rd: ", bnk*256 + i); + show_addr(ptr_rd); + printf(" wr: "); + show_addr(ptr_wr); + printf("\n"); + } +} + +void +show_addr(byte *ptr) +{ + word32 mem_size; + + mem_size = g_mem_size_total; + if(ptr >= g_memory_ptr && ptr < &g_memory_ptr[mem_size]) { + printf("%p--memory[%06x]", ptr, + (word32)(ptr - g_memory_ptr)); + } else if(ptr >= g_rom_fc_ff_ptr && ptr < &g_rom_fc_ff_ptr[256*1024]) { + printf("%p--rom_fc_ff[%06x]", ptr, + (word32)(ptr - g_rom_fc_ff_ptr)); + } else if(ptr >= g_slow_memory_ptr && ptr<&g_slow_memory_ptr[128*1024]){ + printf("%p--slow_memory[%06x]", ptr, + (word32)(ptr - g_slow_memory_ptr)); + } else if(ptr >=g_dummy_memory1_ptr && ptr < &g_dummy_memory1_ptr[256]){ + printf("%p--dummy_memory[%06x]", ptr, + (word32)(ptr - g_dummy_memory1_ptr)); + } else { + printf("%p--unknown", ptr); + } +} + + +#if 0 +#define CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc) \ + fcyc = *cyc_ptr; \ + new_fcyc = (int)(fcyc + g_cur_fplus_ptr->plus_x_minus_1); \ + *cyc_ptr = new_fcyc; \ + dcycs = g_last_vbl_dcycs + new_fcyc; +#endif + +#define CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc) \ + dcycs = g_last_vbl_dcycs + *cyc_ptr; + + +int dummy = 0; + +int +io_read(word32 loc, double *cyc_ptr) +{ + double dcycs; + word64 word64_tmp; +#if 0 + double fcyc, new_fcyc; +#endif + int new_lcbank2; + int new_wrdefram; + int tmp; + int slot; + int i; + + CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); + +/* IO space */ + switch((loc >> 8) & 0xf) { + case 0: /* 0xc000 - 0xc0ff */ + switch(loc & 0xff) { + /* 0xc000 - 0xc00f */ + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return(adb_read_c000()); + + /* 0xc010 - 0xc01f */ + case 0x10: /* c010 */ + return(adb_access_c010()); + case 0x11: /* c011 = RDLCBANK2 */ + return IOR(LCBANK2); + case 0x12: /* c012= RDLCRAM */ + return IOR(!RDROM); + case 0x13: /* c013=rdramd */ + return IOR(RAMRD); + case 0x14: /* c014=rdramwrt */ + return IOR(RAMWRT); + case 0x15: /* c015 = INTCX */ + return IOR(INTCX); + case 0x16: /* c016: ALTZP */ + return IOR(ALTZP); + case 0x17: /* c017: rdc3rom */ + return IOR(int_crom[3]); + case 0x18: /* c018: rd80c0l */ + return IOR((g_cur_a2_stat & ALL_STAT_ST80)); + case 0x19: /* c019: rdvblbar */ + tmp = in_vblank(dcycs); + return IOR(tmp); + case 0x1a: /* c01a: rdtext */ + return IOR(g_cur_a2_stat & ALL_STAT_TEXT); + case 0x1b: /* c01b: rdmix */ + return IOR(g_cur_a2_stat & ALL_STAT_MIX_T_GR); + case 0x1c: /* c01c: rdpage2 */ + return IOR(PAGE2); + case 0x1d: /* c01d: rdhires */ + return IOR(g_cur_a2_stat & ALL_STAT_HIRES); + case 0x1e: /* c01e: altcharset on? */ + return IOR(g_cur_a2_stat & ALL_STAT_ALTCHARSET); + case 0x1f: /* c01f: rd80vid */ + return IOR(g_cur_a2_stat & ALL_STAT_VID80); + + /* 0xc020 - 0xc02f */ + case 0x20: /* 0xc020 */ + /* Click cassette port */ + return 0x00; + case 0x21: /* 0xc021 */ + UNIMPL_READ; + case 0x22: /* 0xc022 */ + return (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; + case 0x23: /* 0xc023 */ + return g_c023_val; + case 0x24: /* 0xc024 */ + return mouse_read_c024(dcycs); + case 0x25: /* 0xc025 */ + return adb_read_c025(); + case 0x26: /* 0xc026 */ + return adb_read_c026(); + case 0x27: /* 0xc027 */ + return adb_read_c027(); + case 0x28: /* 0xc028 */ + UNIMPL_READ; + case 0x29: /* 0xc029 */ + return((g_cur_a2_stat & 0xa0) | (linear_vid<<6) | + (bank1latch)); + case 0x2a: /* 0xc02a */ +#if 0 + printf("Reading c02a...returning 0\n"); +#endif + return 0; + case 0x2b: /* 0xc02b */ + return c02b_val; + case 0x2c: /* 0xc02c */ + /* printf("reading c02c, returning 0\n"); */ + return 0; + case 0x2d: /* 0xc02d */ + tmp = 0; + for(i = 0; i < 8; i++) { + tmp = tmp | (int_crom[i] << i); + } + return tmp; + case 0x2e: /* 0xc02e */ + case 0x2f: /* 0xc02f */ + return read_vid_counters(loc, dcycs); + + /* 0xc030 - 0xc03f */ + case 0x30: /* 0xc030 */ + /* click speaker */ + return doc_read_c030(dcycs); + case 0x31: /* 0xc031 */ + /* 3.5" control */ + return (head_35 << 7) | (g_apple35_sel << 6); + case 0x32: /* 0xc032 */ + /* scan int */ + return 0; + case 0x33: /* 0xc033 = CLOCKDATA*/ + return clock_read_c033(); + case 0x34: /* 0xc034 = CLOCKCTL */ + return clock_read_c034(); + case 0x35: /* 0xc035 */ + return shadow_reg; + case 0x36: /* 0xc036 = CYAREG */ + tmp = (speed_fast << 7) + (power_on_clear << 6) + + (g_shadow_all_banks << 4) + g_slot_motor_detect; + return tmp; + case 0x37: /* 0xc037 */ + return 0; + case 0x38: /* 0xc038 */ + return scc_read_reg(1, dcycs); + case 0x39: /* 0xc039 */ + return scc_read_reg(0, dcycs); + case 0x3a: /* 0xc03a */ + return scc_read_data(1, dcycs); + case 0x3b: /* 0xc03b */ + return scc_read_data(0, dcycs); + case 0x3c: /* 0xc03c */ + /* doc control */ + return doc_read_c03c(dcycs); + case 0x3d: /* 0xc03d */ + return doc_read_c03d(dcycs); + case 0x3e: /* 0xc03e */ + return (doc_ptr & 0xff); + case 0x3f: /* 0xc03f */ + return (doc_ptr >> 8); + + /* 0xc040 - 0xc04f */ + case 0x40: /* 0xc040 */ + /* cassette */ + return 0; + case 0x41: /* 0xc041 */ + tmp = ((c041_en_25sec_ints << 4) + + (c041_en_vbl_ints << 3) + + (c041_en_switch_ints << 2) + + (c041_en_move_ints << 1) + (c041_en_mouse) ); + return tmp; + case 0x45: /* 0xc045 */ + halt_printf("Mega II mouse read: c045\n"); + return 0; + case 0x46: /* 0xc046 */ + tmp = g_c046_val; + g_c046_val = (tmp & 0xbf) + ((tmp & 0x80) >> 1); + return tmp; + case 0x47: /* 0xc047 */ + if(c046_vbl_irq_pending) { + remove_irq(); + c046_vbl_irq_pending = 0; + } + if(c046_25sec_irq_pend) { + remove_irq(); + c046_25sec_irq_pend = 0; + } + g_c046_val &= 0xe7; /* clear vbl_int, 1/4sec int*/ + return 0; + case 0x42: /* 0xc042 */ + case 0x43: /* 0xc043 */ + return 0; + case 0x4f: /* 0xc04f */ + /* for information on c04f, see: */ + /* www.sheppyware.net/tech/hardware/softswitches.html */ + /* write to $c04f to start. Then read $c04f to get */ + /* emulator ($16=sweet16, $fe=bernie II). */ + /* Then read again to get version: $21 == 2.1 */ + switch(g_emubyte_cnt) { + case 1: + g_emubyte_cnt = 2; + return 'K'; + case 2: + g_emubyte_cnt = 0; + tmp = g_kegs_version_str[0] - '0'; + i = g_kegs_version_str[2] - '0'; + return ((tmp & 0xf) << 4) + (i & 0xf); + default: + g_emubyte_cnt = 0; + return 0; + } + case 0x44: /* 0xc044 */ + case 0x48: /* 0xc048 */ + case 0x49: /* 0xc049 */ + case 0x4a: /* 0xc04a */ + case 0x4b: /* 0xc04b */ + case 0x4c: /* 0xc04c */ + case 0x4d: /* 0xc04d */ + case 0x4e: /* 0xc04e */ + UNIMPL_READ; + + /* 0xc050 - 0xc05f */ + case 0x50: /* 0xc050 */ + if(g_cur_a2_stat & ALL_STAT_TEXT) { + g_cur_a2_stat &= (~ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return 0; + case 0x51: /* 0xc051 */ + if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { + g_cur_a2_stat |= (ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return 0; + case 0x52: /* 0xc052 */ + if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { + g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return 0; + case 0x53: /* 0xc053 */ + if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { + g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return 0; + case 0x54: /* 0xc054 */ + set_statereg(dcycs, statereg & (~0x40)); + return 0; + case 0x55: /* 0xc055 */ + set_statereg(dcycs, statereg | 0x40); + return 0; + case 0x56: /* 0xc056 */ + if(g_cur_a2_stat & ALL_STAT_HIRES) { + g_cur_a2_stat &= (~ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return 0; + case 0x57: /* 0xc057 */ + if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { + g_cur_a2_stat |= (ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return 0; + case 0x58: /* 0xc058 */ + if(g_zipgs_unlock < 4) { + annunc_0 = 0; + } + return 0; + case 0x59: /* 0xc059 */ + if(g_zipgs_unlock >= 4) { + return g_zipgs_reg_c059; + } else { + annunc_0 = 1; + } + return 0; + case 0x5a: /* 0xc05a */ + if(g_zipgs_unlock >= 4) { + return g_zipgs_reg_c05a; + } else { + annunc_1 = 0; + } + return 0; + case 0x5b: /* 0xc05b */ + if(g_zipgs_unlock >= 4) { + word64_tmp = (word64)dcycs; + tmp = (word64_tmp >> 9) & 1; + return (tmp << 7) + (g_zipgs_reg_c05b & 0x7f); + } else { + annunc_1 = 1; + } + return 0; + case 0x5c: /* 0xc05c */ + if(g_zipgs_unlock >= 4) { + return g_zipgs_reg_c05c; + } else { + annunc_2 = 0; + } + return 0; + case 0x5d: /* 0xc05d */ + if(g_zipgs_unlock >= 4) { + halt_printf("Reading ZipGS $c05d!\n"); + } else { + annunc_2 = 1; + } + return 0; + case 0x5e: /* 0xc05e */ + if(g_zipgs_unlock >= 4) { + halt_printf("Reading ZipGS $c05e!\n"); + } else if(g_cur_a2_stat & ALL_STAT_ANNUNC3) { + g_cur_a2_stat &= (~ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return 0; + case 0x5f: /* 0xc05f */ + if(g_zipgs_unlock >= 4) { + halt_printf("Reading ZipGS $c05f!\n"); + } else if((g_cur_a2_stat & ALL_STAT_ANNUNC3) == 0) { + g_cur_a2_stat |= (ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return 0; + + + /* 0xc060 - 0xc06f */ + case 0x60: /* 0xc060 */ + return IOR(g_paddle_button[3]); + case 0x61: /* 0xc061 */ + return IOR(adb_is_cmd_key_down() || g_paddle_button[0]); + case 0x62: /* 0xc062 */ + return IOR(adb_is_option_key_down() || + g_paddle_button[1]); + case 0x63: /* 0xc063 */ + return IOR(g_paddle_button[2]); + case 0x64: /* 0xc064 */ + return read_paddles(0, dcycs); + case 0x65: /* 0xc065 */ + return read_paddles(1, dcycs); + case 0x66: /* 0xc066 */ + return read_paddles(2, dcycs); + case 0x67: /* 0xc067 */ + return read_paddles(3, dcycs); + case 0x68: /* 0xc068 = STATEREG */ + return statereg; + case 0x69: /* 0xc069 */ + /* Reserved reg, return 0 */ + return 0; + case 0x6a: /* 0xc06a */ + case 0x6b: /* 0xc06b */ + case 0x6c: /* 0xc06c */ + case 0x6d: /* 0xc06d */ + case 0x6e: /* 0xc06e */ + case 0x6f: /* 0xc06f */ + UNIMPL_READ; + + /* 0xc070 - 0xc07f */ + case 0x70: /* c070 */ + paddle_trigger(dcycs); + return 0; + case 0x71: /* 0xc071 */ + case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + return g_rom_fc_ff_ptr[3*65536 + 0xc000 + (loc & 0xff)]; + + /* 0xc080 - 0xc08f */ + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + new_lcbank2 = ((loc & 0x8) >> 1) ^ 0x4; + new_wrdefram = (loc & 1); + if(new_wrdefram != wrdefram) { + fixup_wrdefram(new_wrdefram); + } + switch(loc & 0x3) { + case 0x1: /* 0xc081 */ + case 0x2: /* 0xc082 */ + /* Read rom, set lcbank2 */ + set_statereg(dcycs, (statereg & ~(0x04)) | + (new_lcbank2 | 0x08)); + break; + case 0x0: /* 0xc080 */ + case 0x3: /* 0xc083 */ + /* Read ram (clear RDROM), set lcbank2 */ + set_statereg(dcycs, (statereg & ~(0x0c)) | + (new_lcbank2)); + break; + } + return 0xa0; + /* 0xc090 - 0xc09f */ + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + /* UNIMPL_READ; */ + return 0; + /* 0xc0a0 - 0xc0af */ + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + return 0; + /* UNIMPL_READ; */ + + /* 0xc0b0 - 0xc0bf */ + case 0xb0: + /* c0b0: female voice tool033 look at this */ + return 0; + case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* UNIMPL_READ; */ + return 0; + /* c0b8: Second Sight card stuff: return 0 */ + case 0xb8: + return 0; + break; + + /* 0xc0c0 - 0xc0cf */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return 0; + /* 0xc0d0 - 0xc0df */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + return 0; + /* 0xc0e0 - 0xc0ef */ + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xed: case 0xee: case 0xef: + return read_iwm(loc, dcycs); + case 0xec: + return iwm_read_c0ec(dcycs); + /* 0xc0f0 - 0xc0ff */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return 0; + + default: + printf("loc: %04x bad\n", loc); + UNIMPL_READ; + } + case 1: case 2: case 3: case 4: case 5: case 6: + /* c100 - c6ff */ + slot = ((loc >> 8) & 7); + if(INTCX || (int_crom[slot] == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + return (dummy++) & 0xff; + case 7: + /* c700 */ + if(INTCX || (int_crom[7] == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + tmp = g_rom_fc_ff_ptr[0x3c500 + (loc & 0xff)]; + if((loc & 0xff) == 0xfb) { + tmp = tmp & 0xbf; /* clear bit 6 for ROM 03 */ + } + return tmp; + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: + if(INTCX || (int_crom[3] == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + UNIMPL_READ; + case 0xf: + if(INTCX || (int_crom[3] == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + if((loc & 0xfff) == 0xfff) { + return g_rom_fc_ff_ptr[0x3cfff]; + } + UNIMPL_READ; + } + + halt_printf("io_read: hit end, loc: %06x\n", loc); + + return 0xff; +} + +void +io_write(word32 loc, int val, double *cyc_ptr) +{ + double dcycs; +#if 0 + double fcyc, new_fcyc; +#endif + int new_tmp; + int new_lcbank2; + int new_wrdefram; + int i; + int tmp, tmp2; + int fixup; + + CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); + + val = val & 0xff; + switch((loc >> 8) & 0xf) { + case 0: /* 0xc000 - 0xc0ff */ + switch(loc & 0xff) { + /* 0xc000 - 0xc00f */ + case 0x00: /* 0xc000 */ + if(g_cur_a2_stat & ALL_STAT_ST80) { + g_cur_a2_stat &= (~ALL_STAT_ST80); + fixup_st80col(dcycs); + } + return; + case 0x01: /* 0xc001 */ + if((g_cur_a2_stat & ALL_STAT_ST80) == 0) { + g_cur_a2_stat |= (ALL_STAT_ST80); + fixup_st80col(dcycs); + } + return; + case 0x02: /* 0xc002 */ + set_statereg(dcycs, statereg & ~0x20); + return; + case 0x03: /* 0xc003 */ + set_statereg(dcycs, statereg | 0x20); + return; + case 0x04: /* 0xc004 */ + set_statereg(dcycs, statereg & ~0x10); + return; + case 0x05: /* 0xc005 */ + set_statereg(dcycs, statereg | 0x10); + return; + case 0x06: /* 0xc006 */ + set_statereg(dcycs, statereg & ~0x01); + return; + case 0x07: /* 0xc007 */ + set_statereg(dcycs, statereg | 0x01); + return; + case 0x08: /* 0xc008 */ + set_statereg(dcycs, statereg & ~0x80); + return; + case 0x09: /* 0xc009 */ + set_statereg(dcycs, statereg | 0x80); + return; + case 0x0a: /* 0xc00a */ + if(int_crom[3] != 0) { + int_crom[3] = 0; + fixup_intcx(); + } + return; + case 0x0b: /* 0xc00b */ + if(int_crom[3] == 0) { + int_crom[3] = 1; + fixup_intcx(); + } + return; + case 0x0c: /* 0xc00c */ + if(g_cur_a2_stat & ALL_STAT_VID80) { + g_cur_a2_stat &= (~ALL_STAT_VID80); + change_display_mode(dcycs); + } + return; + case 0x0d: /* 0xc00d */ + if((g_cur_a2_stat & ALL_STAT_VID80) == 0) { + g_cur_a2_stat |= (ALL_STAT_VID80); + change_display_mode(dcycs); + } + return; + case 0x0e: /* 0xc00e */ + if(g_cur_a2_stat & ALL_STAT_ALTCHARSET) { + g_cur_a2_stat &= (~ALL_STAT_ALTCHARSET); + change_display_mode(dcycs); + } + return; + case 0x0f: /* 0xc00f */ + if((g_cur_a2_stat & ALL_STAT_ALTCHARSET) == 0) { + g_cur_a2_stat |= (ALL_STAT_ALTCHARSET); + change_display_mode(dcycs); + } + return; + /* 0xc010 - 0xc01f */ + 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: + adb_access_c010(); + return; + /* 0xc020 - 0xc02f */ + case 0x20: /* 0xc020 */ + /* WRITE CASSETTE?? */ + return; + case 0x21: /* 0xc021 */ + new_tmp = ((val >> 7) & 1) << + (31 - BIT_ALL_STAT_COLOR_C021); + if((g_cur_a2_stat & ALL_STAT_COLOR_C021) != new_tmp) { + g_cur_a2_stat ^= new_tmp; + change_display_mode(dcycs); + } + return; + case 0x22: /* 0xc022 */ + /* change text color */ + tmp = (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; + if(val != tmp) { + /* change text/bg color! */ + g_cur_a2_stat &= ~(ALL_STAT_TEXT_COLOR | + ALL_STAT_BG_COLOR); + g_cur_a2_stat += (val << BIT_ALL_STAT_BG_COLOR); + change_display_mode(dcycs); + } + return; + case 0x23: /* 0xc023 */ + if((val & 0x19) != 0) { + halt_printf("c023 write of %02x!!!\n",val); + } + tmp = (g_c023_val & 0x70) | (val & 0x0f); + if(((tmp & 0x22)==0x22) && !c023_scan_int_irq_pending){ + c023_scan_int_irq_pending = 1; + add_irq(); + } + if(!(tmp & 2) && c023_scan_int_irq_pending) { + c023_scan_int_irq_pending = 0; + remove_irq(); + } + if(((tmp & 0x44)==0x44)&& !c023_1sec_int_irq_pending){ + c023_1sec_int_irq_pending = 1; + add_irq(); + } + if(!(tmp & 0x4) && c023_1sec_int_irq_pending) { + c023_1sec_int_irq_pending = 0; + remove_irq(); + } + + if(c023_1sec_int_irq_pending || + c023_scan_int_irq_pending) { + tmp |= 0x80; + } + g_c023_val = tmp; + return; + case 0x24: /* 0xc024 */ + /* Write to mouse reg: Throw it away */ + return; + case 0x26: /* 0xc026 */ + adb_write_c026(val); + return; + case 0x27: /* 0xc027 */ + adb_write_c027(val); + return; + case 0x29: /* 0xc029 */ + bank1latch = val & 1; + linear_vid = (val >> 6) & 1; + new_tmp = val & 0xa0; + if(bank1latch == 0) { + halt_printf("c029: %02x\n", val); + } + if(new_tmp != (g_cur_a2_stat & 0xa0)) { + g_cur_a2_stat = (g_cur_a2_stat & (~0xa0)) + + new_tmp; + change_display_mode(dcycs); + } + return; + case 0x2a: /* 0xc02a */ +#if 0 + printf("Writing c02a with %02x\n", val); +#endif + return; + case 0x2b: /* 0xc02b */ + c02b_val = val; + if(val != 0x08 && val != 0x00) { + printf("Writing c02b with %02x\n", val); + } + return; + case 0x2d: /* 0xc02d */ + if((val & 0x9) != 0) { + halt_printf("Illegal c02d write: %02x!\n", val); + } + fixup = 0; + for(i = 0; i < 8; i++) { + tmp = ((val & (1 << i)) != 0); + if(int_crom[i] != tmp) { + fixup = 1; + int_crom[i] = tmp; + } + } + if(fixup) { + vid_printf("Write c02d of %02x\n", val); + fixup_intcx(); + } + return; + case 0x28: /* 0xc028 */ + case 0x2c: /* 0xc02c */ + UNIMPL_WRITE; + case 0x25: /* 0xc025 */ + /* Space Shark writes to c025--ignore */ + case 0x2e: /* 0xc02e */ + case 0x2f: /* 0xc02f */ + /* Modulae writes to this--just ignore them */ + return; + break; + + /* 0xc030 - 0xc03f */ + case 0x30: /* 0xc030 */ +#if 0 + printf("Write speaker?\n"); +#endif + (void)doc_read_c030(dcycs); + return; + case 0x31: /* 0xc031 */ + tmp = ((val & 0x80) != 0); + tmp2 = ((val & 0x40) != 0); + head_35 = tmp; + iwm_set_apple35_sel(tmp2); + iwm_printf("write c031: %02x, h: %d, 35: %d\n", + val, head_35, g_apple35_sel); + return; + case 0x32: /* 0xc032 */ + tmp = g_c023_val & 0x7f; + if(((val & 0x40) == 0) && (tmp & 0x40)) { + /* clear 1 sec int */ + irq_printf("Clear 1sec int\n"); + if(c023_1sec_int_irq_pending) { + remove_irq(); + } + tmp &= 0xbf; + g_c023_val = tmp; + c023_1sec_int_irq_pending = 0; + } + if(((val & 0x20) == 0) && (tmp & 0x20)) { + /* clear scan line int */ + irq_printf("Clear scn int1\n"); + if(c023_scan_int_irq_pending) { + remove_irq(); + } + c023_scan_int_irq_pending = 0; + g_c023_val = tmp & 0xdf; + check_for_new_scan_int(dcycs); + } + if(c023_1sec_int_irq_pending || + c023_scan_int_irq_pending) { + g_c023_val |= 0x80; + } + if((val & 0x9f) != 0x9f) { + irq_printf("c032: wrote %02x!\n", val); + } + return; + case 0x33: /* 0xc033 = CLOCKDATA*/ + clock_write_c033(val); + return; + case 0x34: /* 0xc034 = CLOCKCTL */ + clock_write_c034(val); + if((val & 0xf) != g_border_color) { + g_border_color = val & 0xf; + change_border_color(dcycs, val & 0xf); + } + return; + case 0x35: /* 0xc035 */ + update_shadow_reg(val); + return; + case 0x36: /* 0xc036 = CYAREG */ + tmp = (val>>7) & 1; + if(speed_fast != tmp) { + /* to recalculate times */ + set_halt(HALT_EVENT); + } + speed_fast = tmp; + if((val & 0xf) != (int)g_slot_motor_detect) { + set_halt(HALT_EVENT); + } + g_slot_motor_detect = (val & 0xf); + + power_on_clear = (val >> 6) & 1; + if((val & 0x60) != 0) { + halt_printf("c036: %2x\n", val); + } + tmp = (val >> 4) & 1; + if(tmp != g_shadow_all_banks) { + if(g_num_shadow_all_banks++ == 0) { + printf("Shadowing all banks...This " + "must be the NFC Megademo\n"); + } + g_shadow_all_banks = tmp; + fixup_shadow_all_banks(); + } + return; + case 0x37: /* 0xc037 */ + /* just ignore, probably someone writing c036 m=0 */ + return; + case 0x38: /* 0xc038 */ + scc_write_reg(1, val, dcycs); + return; + case 0x39: /* 0xc039 */ + scc_write_reg(0, val, dcycs); + return; + case 0x3a: /* 0xc03a */ + scc_write_data(1, val, dcycs); + return; + case 0x3b: /* 0xc03b */ + scc_write_data(0, val, dcycs); + return; + case 0x3c: /* 0xc03c */ + /* doc ctl */ + doc_write_c03c(val, dcycs); + return; + case 0x3d: /* 0xc03d */ + /* doc data reg */ + doc_write_c03d(val, dcycs); + return; + case 0x3e: /* 0xc03e */ + doc_write_c03e(val); + return; + case 0x3f: /* 0xc03f */ + doc_write_c03f(val); + return; + + /* 0xc040 - 0xc04f */ + case 0x41: /* c041 */ + c041_en_25sec_ints = ((val & 0x10) != 0); + c041_en_vbl_ints = ((val & 0x8) != 0); + c041_en_switch_ints = ((val & 0x4) != 0); + c041_en_move_ints = ((val & 0x2) != 0); + c041_en_mouse = ((val & 0x1) != 0); + if((val & 0xe7) != 0) { + halt_printf("write c041: %02x\n", val); + } + + if(!c041_en_vbl_ints && c046_vbl_irq_pending) { + /* there was an interrupt, but no more*/ + remove_irq(); + c046_vbl_irq_pending = 0; + } + if(!c041_en_25sec_ints && c046_25sec_irq_pend) { + /* there was an interrupt, but no more*/ + remove_irq(); + c046_25sec_irq_pend = 0; + } + return; + case 0x46: /* c046 */ + /* ignore writes to c046 */ + return; + case 0x47: /* c047 */ + if(c046_vbl_irq_pending) { + remove_irq(); + c046_vbl_irq_pending = 0; + } + if(c046_25sec_irq_pend) { + remove_irq(); + c046_25sec_irq_pend = 0; + } + g_c046_val &= 0xe7; /* clear vblint, 1/4sec int*/ + return; + case 0x48: /* c048 */ + /* diversitune writes this--ignore it */ + return; + case 0x42: /* c042 */ + case 0x43: /* c043 */ + return; + case 0x4f: /* c04f */ + g_emubyte_cnt = 1; + return; + case 0x40: /* c040 */ + case 0x44: /* c044 */ + case 0x45: /* c045 */ + case 0x49: /* c049 */ + case 0x4a: /* c04a */ + case 0x4b: /* c04b */ + case 0x4c: /* c04c */ + case 0x4d: /* c04d */ + case 0x4e: /* c04e */ + UNIMPL_WRITE; + + /* 0xc050 - 0xc05f */ + case 0x50: /* 0xc050 */ + if(g_cur_a2_stat & ALL_STAT_TEXT) { + g_cur_a2_stat &= (~ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return; + case 0x51: /* 0xc051 */ + if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { + g_cur_a2_stat |= (ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return; + case 0x52: /* 0xc052 */ + if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { + g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return; + case 0x53: /* 0xc053 */ + if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { + g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return; + case 0x54: /* 0xc054 */ + set_statereg(dcycs, statereg & (~0x40)); + return; + case 0x55: /* 0xc055 */ + set_statereg(dcycs, statereg | 0x40); + return; + case 0x56: /* 0xc056 */ + if(g_cur_a2_stat & ALL_STAT_HIRES) { + g_cur_a2_stat &= (~ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return; + case 0x57: /* 0xc057 */ + if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { + g_cur_a2_stat |= (ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return; + case 0x58: /* 0xc058 */ + if(g_zipgs_unlock >= 4) { + g_zipgs_reg_c059 &= 0x4; /* last reset cold */ + } else { + annunc_0 = 0; + } + return; + case 0x59: /* 0xc059 */ + if(g_zipgs_unlock >= 4) { + g_zipgs_reg_c059 = (val & 0xf8) | + (g_zipgs_reg_c059 & 0x7); + } else { + annunc_0 = 1; + } + return; + case 0x5a: /* 0xc05a */ + annunc_1 = 0; + if((val & 0xf0) == 0x50) { + g_zipgs_unlock++; + } else if((val & 0xf0) == 0xa0) { + g_zipgs_unlock = 0; + } else if(g_zipgs_unlock >= 4) { + if((g_zipgs_reg_c05b & 0x10) == 0) { + /* to recalculate times */ + set_halt(HALT_EVENT); + } + g_zipgs_reg_c05b |= 0x10; // disable + } + return; + case 0x5b: /* 0xc05b */ + if(g_zipgs_unlock >= 4) { + if((g_zipgs_reg_c05b & 0x10) != 0) { + /* to recalculate times */ + set_halt(HALT_EVENT); + } + g_zipgs_reg_c05b &= (~0x10); // enable + } else { + annunc_1 = 1; + } + return; + case 0x5c: /* 0xc05c */ + if(g_zipgs_unlock >= 4) { + g_zipgs_reg_c05c = val; + } else { + annunc_2 = 0; + } + return; + case 0x5d: /* 0xc05d */ + if(g_zipgs_unlock >= 4) { + if(((g_zipgs_reg_c05a ^ val) >= 0x10) && + ((g_zipgs_reg_c05b & 0x10) == 0)) { + set_halt(HALT_EVENT); + } + g_zipgs_reg_c05a = val | 0xf; + } else { + annunc_2 = 1; + } + return; + case 0x5e: /* 0xc05e */ + if(g_zipgs_unlock >= 4) { + /* Zippy writes 0x80 and 0x00 here... */ + } else if(g_cur_a2_stat & ALL_STAT_ANNUNC3) { + g_cur_a2_stat &= (~ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return; + case 0x5f: /* 0xc05f */ + if(g_zipgs_unlock >= 4) { + halt_printf("Wrote ZipGS $c05f: %02x\n", val); + } else if((g_cur_a2_stat & ALL_STAT_ANNUNC3) == 0) { + g_cur_a2_stat |= (ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return; + + + /* 0xc060 - 0xc06f */ + case 0x60: /* 0xc060 */ + case 0x61: /* 0xc061 */ + case 0x62: /* 0xc062 */ + case 0x63: /* 0xc063 */ + case 0x64: /* 0xc064 */ + case 0x65: /* 0xc065 */ + case 0x66: /* 0xc066 */ + case 0x67: /* 0xc067 */ + /* all the above do nothing--return */ + return; + case 0x68: /* 0xc068 = STATEREG */ + set_statereg(dcycs, val); + return; + case 0x69: /* 0xc069 */ + /* just ignore, someone writing c068 with m=0 */ + return; + case 0x6a: /* 0xc06a */ + case 0x6b: /* 0xc06b */ + case 0x6c: /* 0xc06c */ + case 0x6d: /* 0xc06d */ + case 0x6e: /* 0xc06e */ + case 0x6f: /* 0xc06f */ + UNIMPL_WRITE; + + /* 0xc070 - 0xc07f */ + case 0x70: /* 0xc070 = Trigger paddles */ + paddle_trigger(dcycs); + return; + case 0x73: /* 0xc073 = multibank ram card bank addr? */ + return; + case 0x71: /* 0xc071 = another multibank ram card enable? */ + case 0x7e: /* 0xc07e */ + case 0x7f: /* 0xc07f */ + return; + case 0x72: /* 0xc072 */ + case 0x74: /* 0xc074 */ + case 0x75: /* 0xc075 */ + case 0x76: /* 0xc076 */ + case 0x77: /* 0xc077 */ + case 0x78: /* 0xc078 */ + case 0x79: /* 0xc079 */ + case 0x7a: /* 0xc07a */ + case 0x7b: /* 0xc07b */ + case 0x7c: /* 0xc07c */ + case 0x7d: /* 0xc07d */ + UNIMPL_WRITE; + + /* 0xc080 - 0xc08f */ + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + new_lcbank2 = ((loc & 0x8) >> 1) ^ 0x4; + new_wrdefram = (loc & 1); + if(new_wrdefram != wrdefram) { + fixup_wrdefram(new_wrdefram); + } + switch(loc & 0xf) { + case 0x1: /* 0xc081 */ + case 0x2: /* 0xc082 */ + case 0x5: /* 0xc085 */ + case 0x6: /* 0xc086 */ + case 0x9: /* 0xc089 */ + case 0xa: /* 0xc08a */ + case 0xd: /* 0xc08d */ + case 0xe: /* 0xc08e */ + /* Read rom, set lcbank2 */ + set_statereg(dcycs, (statereg & ~(0x04)) | + (new_lcbank2 | 0x08)); + break; + case 0x0: /* 0xc080 */ + case 0x3: /* 0xc083 */ + case 0x4: /* 0xc084 */ + case 0x7: /* 0xc087 */ + case 0x8: /* 0xc088 */ + case 0xb: /* 0xc08b */ + case 0xc: /* 0xc08c */ + case 0xf: /* 0xc08f */ + /* Read ram (clear RDROM), set lcbank2 */ + set_statereg(dcycs, (statereg & ~(0x0c)) | + (new_lcbank2)); + break; + } + return; + + /* 0xc090 - 0xc09f */ + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + UNIMPL_WRITE; + + /* 0xc0a0 - 0xc0af */ + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + UNIMPL_WRITE; + case 0xa8: + /* Kurzweil SMP writes to 0xc0a8, ignore it */ + return; + + /* 0xc0b0 - 0xc0bf */ + case 0xb0: + /* Second sight stuff--ignore it */ + return; + case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + UNIMPL_WRITE; + + /* 0xc0c0 - 0xc0cf */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + UNIMPL_WRITE; + + /* 0xc0d0 - 0xc0df */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + UNIMPL_WRITE; + + /* 0xc0e0 - 0xc0ef */ + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + write_iwm(loc, val, dcycs); + return; + + /* 0xc0f0 - 0xc0ff */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + UNIMPL_WRITE; + default: + printf("WRite loc: %x\n",loc); + exit(-300); + } + break; + case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* c1000 - c7ff */ + UNIMPL_WRITE; + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: + UNIMPL_WRITE; + case 0xf: + if((loc & 0xfff) == 0xfff) { + /* cfff */ + return; + } + UNIMPL_WRITE; + } + printf("Huh2? Write loc: %x\n", loc); + exit(-290); +} + + + +#if 0 +int +get_slow_mem(word32 loc, int duff_cycles) +{ + int val; + + loc = loc & 0x1ffff; + + if((loc &0xf000) == 0xc000) { + return(io_read(loc &0xfff, duff_cycles)); + } + if((loc & 0xf000) >= 0xd000) { + if((loc & 0xf000) == 0xd000) { + if(!LCBANK2) { + /* Not LCBANK2 == be 0xc000 - 0xd000 */ + loc = loc - 0x1000; + } + } + } + + val = g_slow_memory_ptr[loc]; + + halt_printf("get_slow_mem: %06x = %02x\n", loc, val); + + return val; +} + +int +set_slow_mem(word32 loc, int val, int duff_cycles) +{ + int or_pos; + word32 or_val; + + loc = loc & 0x1ffff; + if((loc & 0xf000) == 0xc000) { + return(io_write(loc & 0xfff, val, duff_cycles)); + } + + if((loc & 0xf000) == 0xd000) { + if(!LCBANK2) { + /* Not LCBANK2 == be 0xc000 - 0xd000 */ + loc = loc - 0x1000; + } + } + + if(g_slow_memory_ptr[loc] != val) { + or_pos = (loc >> SHIFT_PER_CHANGE) & 0x1f; + or_val = DEP1(1, or_pos, 0); + if((loc >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE || loc < 0) { + printf("loc: %08x!!\n", loc); + exit(11); + } + slow_mem_changed[(loc & 0xffff) >> CHANGE_SHIFT] |= or_val; + } + +/* doesn't shadow text/hires graphics properly! */ + g_slow_memory_ptr[loc] = val; + + return val; +} +#endif + +/* IIgs vertical line counters */ +/* 0x7d - 0x7f: in vbl, top of screen? */ +/* 0x80 - 0xdf: not in vbl, drawing screen */ +/* 0xe0 - 0xff: in vbl, bottom of screen */ + +/* Note: lines are then 0-0x60 effectively, for 192 lines */ +/* vertical blanking engages on line 192, even if in super hires mode */ +/* (Last 8 lines in SHR are drawn with vbl_active set */ + +word32 +get_lines_since_vbl(double dcycs) +{ + double dcycs_since_last_vbl; + double dlines_since_vbl; + double dcyc_line_start; + word32 lines_since_vbl; + int offset; + + dcycs_since_last_vbl = dcycs - g_last_vbl_dcycs; + + dlines_since_vbl = (262.0/DCYCS_IN_16MS) * dcycs_since_last_vbl; + lines_since_vbl = (int)dlines_since_vbl; + dcyc_line_start = (double)lines_since_vbl * (DCYCS_IN_16MS/262.0); + + offset = ((int)(dcycs_since_last_vbl - dcyc_line_start)) & 0xff; + + lines_since_vbl = (lines_since_vbl << 8) + offset; + + if(lines_since_vbl < 0x10680) { + return lines_since_vbl; + } else { + halt_printf("lines_since_vbl: %08x!\n", lines_since_vbl); + printf("dc_s_l_v: %f, dcycs: %f, last_vbl_cycs: %f\n", + dcycs_since_last_vbl, dcycs, g_last_vbl_dcycs); + show_dtime_array(); + show_all_events(); + /* U_STACK_TRACE(); */ + } + + return lines_since_vbl; +} + + +int +in_vblank(double dcycs) +{ + int lines_since_vbl; + + lines_since_vbl = get_lines_since_vbl(dcycs); + + if(lines_since_vbl >= 0xc000) { + return 1; + } + + return 0; +} + +/* horizontal video counter goes from 0x00,0x40 - 0x7f, then 0x80,0xc0-0xff */ +/* over 2*65 cycles. The last visible screen pos is 0x7f and 0xff */ +/* This matches KEGS starting line 0 at the border for line -1 */ +int +read_vid_counters(int loc, double dcycs) +{ + word32 mask; + int lines_since_vbl; + + loc = loc & 0xf; + + lines_since_vbl = get_lines_since_vbl(dcycs); + + lines_since_vbl += 0x10000; + if(lines_since_vbl >= 0x20000) { + lines_since_vbl = lines_since_vbl - 0x20000 + 0xfa00; + } + + if(lines_since_vbl > 0x1ffff) { + halt_printf("lines_since_vbl: %04x, dcycs: %f, last_vbl: %f\n", + lines_since_vbl, dcycs, g_last_vbl_dcycs); + } + + if(loc == 0xe) { + /* Vertical count */ + return (lines_since_vbl >> 9) & 0xff; + } + + mask = (lines_since_vbl >> 1) & 0x80; + + lines_since_vbl = (lines_since_vbl & 0xff); + if(lines_since_vbl >= 0x01) { + lines_since_vbl = (lines_since_vbl + 0x3f) & 0x7f; + } + return (mask | (lines_since_vbl & 0xff)); +} + diff --git a/src/objects.xib b/src/objects.xib new file mode 100644 index 0000000..616ea10 --- /dev/null +++ b/src/objects.xib @@ -0,0 +1,169 @@ + + + IBCarbonFramework + + NSApplication + + + + main + + + KEGSMAC + + KEGSMAC + + + About KEGSMAC + 0 + abou + + + TRUE + + + Quit + 0 + quit + + + _NSAppleMenu + + + + File + + File + + + Configuration F4 + 0 + KCFG + Enter KEGS Configuration Panel + + + + + + Window + + Window + + + Zoom Window + zoom + + + TRUE + Minimize Window + 0 + mini + + + TRUE + Minimize All Windows + 0 + mina + + + TRUE + + + TRUE + Bring All to Front + bfrt + + + TRUE + Arrange in Front + 1572864 + frnt + + + _NSWindowsMenu + + + + _NSMainMenu + + + + + Window + + Window + + + TRUE + Minimize Window + m + mini + + + TRUE + Minimize All Windows + m + 1572864 + mini + + + TRUE + + + TRUE + Bring All to Front + frnt + + + TRUE + Bring in Front + 1572864 + frnt + + + _NSWindowsMenu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Files Owner + + MenuBar + + + 201 + diff --git a/src/op_routs.h b/src/op_routs.h new file mode 100644 index 0000000..a8d6489 --- /dev/null +++ b/src/op_routs.h @@ -0,0 +1,466 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef ASM +# ifdef INCLUDE_RCSID_S + .data + .export rcsdif_op_routs_h,data +rcsdif_op_routs_h + .stringz "@(#)$KmKId: op_routs.h,v 1.40 2004-01-10 15:49:46-05 kentd Exp $" + .code +# endif + + .import get_mem_b0_16,code + .import get_mem_b0_8,code + + .export op_routs_start,data +op_routs_start .word 0 +#endif /* ASM */ + +#ifdef ASM +# define CMP_INDEX_REG_MEAT8(index_reg) \ + extru ret0,31,8,ret0 ! \ + ldi 0xff,scratch3 ! \ + subi 0x100,ret0,ret0 ! \ + add index_reg,ret0,ret0 ! \ + extru ret0,23,1,scratch1 ! \ + and ret0,scratch3,zero ! \ + extru ret0,24,1,neg ! \ + b dispatch ! \ + dep scratch1,31,1,psr + +# define CMP_INDEX_REG_MEAT16(index_reg) \ + extru ret0,31,16,ret0 ! \ + ldil l%0x10000,scratch2 ! \ + zdepi -1,31,16,scratch3 ! \ + sub scratch2,ret0,ret0 ! \ + add index_reg,ret0,ret0 ! \ + extru ret0,15,1,scratch1 ! \ + and ret0,scratch3,zero ! \ + extru ret0,16,1,neg ! \ + b dispatch ! \ + dep scratch1,31,1,psr + +# define CMP_INDEX_REG_LOAD(new_label, index_reg) \ + bb,>=,n psr,27,new_label ! \ + bl get_mem_long_8,link ! \ + nop ! \ + CMP_INDEX_REG_MEAT8(index_reg) ! \ + .label new_label ! \ + bl get_mem_long_16,link ! \ + nop ! \ + CMP_INDEX_REG_MEAT16(index_reg) +#endif + + +#ifdef ASM +#define GET_DLOC_X_IND_WR() \ + CYCLES_PLUS_1 ! \ + add xreg,direct,scratch2 ! \ + INC_KPC_2 ! \ + add scratch2,arg0,arg0 ! \ + bl get_mem_b0_direct_page_16,link ! \ + extru arg0,31,16,arg0 ! \ + copy ret0,arg0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + dep dbank,15,8,arg0 +#else /* C */ +# define GET_DLOC_X_IND_WR() \ + CYCLES_PLUS_1; \ + INC_KPC_2; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + arg = arg + xreg + direct; \ + GET_MEMORY_DIRECT_PAGE16(arg & 0xffff, arg); \ + arg = (dbank << 16) + arg; +#endif + + +#ifdef ASM +# define GET_DLOC_X_IND_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_X_IND_WR() +#else /* C */ +# define GET_DLOC_X_IND_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_X_IND_WR() +#endif + +#ifdef ASM +# define GET_DISP8_S_WR() \ + CYCLES_PLUS_1 ! \ + add stack,arg0,arg0 ! \ + INC_KPC_2 ! \ + extru arg0,31,16,arg0 +#else /* C */ +#define GET_DISP8_S_WR() \ + CYCLES_PLUS_1; \ + arg = (arg + stack) & 0xffff; \ + INC_KPC_2; +#endif + + +#ifdef ASM +# define GET_DISP8_S_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DISP8_S_WR() +#else /* C */ +# define GET_DISP8_S_ADDR() \ + GET_1BYTE_ARG; \ + GET_DISP8_S_WR() +#endif + +#ifdef ASM +# define GET_DLOC_WR() \ + INC_KPC_2 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + add direct,arg0,arg0 ! \ + extru arg0,31,16,arg0 +#else /* C */ +# define GET_DLOC_WR() \ + arg = (arg + direct) & 0xffff; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; +#endif + +#ifdef ASM +# define GET_DLOC_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_WR() +#else /* C */ +# define GET_DLOC_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_WR() +#endif + +#ifdef ASM +# define GET_DLOC_L_IND_WR() \ + INC_KPC_2 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_24,link ! \ + extru arg0,31,16,arg0 ! \ + copy ret0,arg0 +#else /* C */ +# define GET_DLOC_L_IND_WR() \ + arg = (arg + direct) & 0xffff; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + INC_KPC_2; \ + GET_MEMORY24(arg, arg, 1); +#endif + + +#ifdef ASM +# define GET_DLOC_L_IND_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_L_IND_WR() +#else /* C */ +# define GET_DLOC_L_IND_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_L_IND_WR() +#endif + +#ifdef ASM +# define GET_DLOC_IND_Y_ADDR_FOR_WR() \ + ldb 1(scratch1),arg0 ! \ + CYCLES_PLUS_1 ! \ + GET_DLOC_IND_Y_WR_SPECIAL() +#else /* C */ +# define GET_DLOC_IND_Y_ADDR_FOR_WR() \ + GET_1BYTE_ARG; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, tmp1); \ + tmp1 += (dbank << 16); \ + arg = tmp1 + yreg; \ + CYCLES_PLUS_1; \ + INC_KPC_2; +#endif + + +#ifdef ASM +# define GET_DLOC_IND_WR() \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + INC_KPC_2 ! \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_direct_page_16,link ! \ + extru arg0,31,16,arg0 ! \ + copy ret0,arg0 ! \ + dep dbank,15,16,arg0 +#else /* C */ +# define GET_DLOC_IND_WR() \ + INC_KPC_2; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + GET_MEMORY_DIRECT_PAGE16((direct + arg) & 0xffff, arg); \ + arg = (dbank << 16) + arg; +#endif + + +#ifdef ASM +# define GET_DLOC_IND_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_IND_WR() +#else +# define GET_DLOC_IND_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_IND_WR(); +#endif + +#ifdef ASM +#define GET_DLOC_INDEX_WR(index_reg) \ + GET_DLOC_INDEX_WR_A(index_reg) ! GET_DLOC_INDEX_WR_B(index_reg) + +#define GET_DLOC_INDEX_WR_A(index_reg) \ + CYCLES_PLUS_1 ! \ + add index_reg,direct,scratch2 ! \ + extru direct,23,8,scratch1 ! \ + INC_KPC_2 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + bb,>= psr,23,.+16 ! \ +/* 4*/ add scratch2,arg0,arg0 ! \ +/* 8*/ extru,<> direct,31,8,0 ! \ +/*12*/ dep scratch1,23,8,arg0 + +/* GET_DLOC_INDeX_WR_B must be exactly one instruction! */ +#define GET_DLOC_INDEX_WR_B(index_reg) \ +/*16*/ extru arg0,31,16,arg0 + +#define GET_DLOC_Y_WR() \ + GET_DLOC_INDEX_WR(yreg) + +#define GET_DLOC_X_WR() \ + GET_DLOC_INDEX_WR(xreg) + +#define GET_DLOC_Y_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_Y_WR() + +# define GET_DLOC_X_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_X_WR() + +#else +# define GET_DLOC_INDEX_WR(index_reg) \ + CYCLES_PLUS_1; \ + arg = (arg & 0xff) + index_reg; \ + INC_KPC_2; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + if((psr & 0x100) && ((direct & 0xff) == 0)) { \ + arg = (arg & 0xff); \ + } \ + arg = (arg + direct) & 0xffff; + +# define GET_DLOC_X_WR() \ + GET_DLOC_INDEX_WR(xreg) +# define GET_DLOC_Y_WR() \ + GET_DLOC_INDEX_WR(yreg) + +# define GET_DLOC_X_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_INDEX_WR(xreg) + +# define GET_DLOC_Y_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_INDEX_WR(yreg) +#endif + + +#ifdef ASM +# define GET_DISP8_S_IND_Y_WR() \ + add stack,arg0,arg0 ! \ + bl get_mem_b0_16,link ! \ + extru arg0,31,16,arg0 ! \ + dep dbank,15,16,ret0 ! \ + CYCLES_PLUS_2 ! \ + add ret0,yreg,arg0 ! \ + INC_KPC_2 ! \ + extru arg0,31,24,arg0 + +# define GET_DISP8_S_IND_Y_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DISP8_S_IND_Y_WR() +#else /* C */ + +# define GET_DISP8_S_IND_Y_WR() \ + arg = (stack + arg) & 0xffff; \ + GET_MEMORY16(arg,arg,1); \ + CYCLES_PLUS_2; \ + arg += (dbank << 16); \ + INC_KPC_2; \ + arg = (arg + yreg) & 0xffffff; + +# define GET_DISP8_S_IND_Y_ADDR() \ + GET_1BYTE_ARG; \ + GET_DISP8_S_IND_Y_WR() +#endif + + +#ifdef ASM +# define GET_DLOC_L_IND_Y_WR() \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + INC_KPC_2 ! \ + add direct,arg0,arg0 ! \ + bl get_mem_b0_24,link ! \ + extru arg0,31,16,arg0 ! \ + add ret0,yreg,arg0 ! \ + extru arg0,31,24,arg0 + +# define GET_DLOC_L_IND_Y_ADDR() \ + ldb 1(scratch1),arg0 ! \ + GET_DLOC_L_IND_Y_WR() +#else /* C */ + +# define GET_DLOC_L_IND_Y_WR() \ + arg = (direct + arg) & 0xffff; \ + if(direct & 0xff) { \ + CYCLES_PLUS_1; \ + } \ + GET_MEMORY24(arg,arg,1); \ + INC_KPC_2; \ + arg = (arg + yreg) & 0xffffff; + +# define GET_DLOC_L_IND_Y_ADDR() \ + GET_1BYTE_ARG; \ + GET_DLOC_L_IND_Y_WR() +#endif + + +#ifdef ASM +# define GET_ABS_ADDR() \ + ldb 1(scratch1),arg0 ! \ + ldb 2(scratch1),scratch1 ! \ + CYCLES_PLUS_1 ! \ + dep dbank,15,8,arg0 ! \ + INC_KPC_3 ! \ + dep scratch1,23,8,arg0 + +# define GET_LONG_ADDR() \ + ldb 1(scratch1),arg0 ! \ + ldb 2(scratch1),scratch2 ! \ + CYCLES_PLUS_2 ! \ + ldb 3(scratch1),scratch1 ! \ + INC_KPC_4 ! \ + dep scratch2,23,8,arg0 ! \ + dep scratch1,15,8,arg0 +#else /* C */ + +# define GET_ABS_ADDR() \ + GET_2BYTE_ARG; \ + CYCLES_PLUS_1; \ + arg = arg + (dbank << 16); \ + INC_KPC_3; + +# define GET_LONG_ADDR() \ + GET_3BYTE_ARG; \ + CYCLES_PLUS_2; \ + INC_KPC_4; +#endif + +#ifdef ASM +#define GET_ABS_INDEX_ADDR_FOR_WR(index_reg) \ + ldb 1(scratch1),arg0 ! \ + copy index_reg,scratch3 ! \ + ldb 2(scratch1),scratch2 ! \ + dep dbank,15,8,scratch3 ! \ + INC_KPC_3 ! \ + dep scratch2,23,8,arg0 ! \ + CYCLES_PLUS_2 ! \ + add arg0,scratch3,arg0 ! \ + extru arg0,31,24,arg0 + +#define GET_LONG_X_ADDR_FOR_WR() \ + ldb 3(scratch1),scratch2 ! \ + copy xreg,scratch3 ! \ + ldb 1(scratch1),arg0 ! \ + ldb 2(scratch1),scratch1 ! \ + CYCLES_PLUS_2 ! \ + dep scratch2,15,8,scratch3 ! \ + INC_KPC_4 ! \ + dep scratch1,23,8,arg0 ! \ + add arg0,scratch3,arg0 ! \ + extru arg0,31,24,arg0 +#else /* C */ + +#define GET_ABS_INDEX_ADDR_FOR_WR(index_reg) \ + GET_2BYTE_ARG; \ + arg = arg + (dbank << 16); \ + INC_KPC_3; \ + CYCLES_PLUS_2; \ + arg = (arg + index_reg) & 0xffffff; + +#define GET_LONG_X_ADDR_FOR_WR() \ + GET_3BYTE_ARG; \ + INC_KPC_4; \ + arg = (arg + xreg) & 0xffffff; \ + CYCLES_PLUS_2; + +#endif /* ASM */ + + +#ifdef ASM + .export op_routs_end,data +op_routs_end .word 0 + + +#define GET_DLOC_IND_Y_WR_SPECIAL() \ + add direct,arg0,arg0 ! \ + extru,= direct,31,8,0 ! \ + CYCLES_PLUS_1 ! \ + bl get_mem_b0_direct_page_16,link ! \ + extru arg0,31,16,arg0 ! \ + dep dbank,15,8,ret0 ! \ + INC_KPC_2 ! \ + add yreg,ret0,arg0 /* don't change this instr */ + /* or add any after */ + /* to preserve ret0 & arg0 */ + + +/* cycle calc: if yreg is 16bit or carry into 2nd byte, inc cycle */ +/* So, if y==16bit, add 1. If x==8bit, add 1 if carry */ +get_dloc_ind_y_rd_8 + stw link,STACK_SAVE_OP_LINK(sp) + GET_DLOC_IND_Y_WR_SPECIAL() + xor arg0,ret0,scratch1 + extru,= psr,27,1,0 + extru,= scratch1,23,8,0 + CYCLES_PLUS_1 + b get_mem_long_8 + ldw STACK_SAVE_OP_LINK(sp),link + +get_dloc_ind_y_rd_16 + stw link,STACK_SAVE_OP_LINK(sp) + GET_DLOC_IND_Y_WR_SPECIAL() + xor arg0,ret0,scratch1 + extru,= psr,27,1,0 + extru,= scratch1,23,8,0 + CYCLES_PLUS_1 + b get_mem_long_16 + ldw STACK_SAVE_OP_LINK(sp),link + + + +#endif /* ASM */ + diff --git a/src/paddles.c b/src/paddles.c new file mode 100644 index 0000000..ec62a0e --- /dev/null +++ b/src/paddles.c @@ -0,0 +1,114 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_paddles_c[] = "@(#)$KmKId: paddles.c,v 1.7 2004-03-23 17:28:06-05 kentd Exp $"; + +#include "defc.h" + +extern int g_mouse_fifo_x[]; /* from adb.c */ +extern int g_mouse_fifo_y[]; + +double g_paddle_trig_dcycs = 0.0; +int g_swap_paddles = 0; +int g_invert_paddles = 0; + +int g_joystick_type = JOYSTICK_MOUSE; + +int g_paddle_button[4] = { 0, 0, 0, 0 }; + /* g_paddle_button[0] = button 0, etc */ + +int g_paddle_val[4] = { 0, 0, 0, 0 }; + /* g_paddle_val[0]: Joystick X coord, [1]:Y coord */ + + +void +paddle_trigger(double dcycs) +{ + /* Called by read/write to $c070 */ + g_paddle_trig_dcycs = dcycs; + + /* Determine what all the paddle values are right now */ + + switch(g_joystick_type) { + case JOYSTICK_MOUSE: + paddle_trigger_mouse(dcycs); + break; + case JOYSTICK_LINUX: + case JOYSTICK_WIN32_1: + case JOYSTICK_WIN32_2: + joystick_update(); + } +} + +void +paddle_trigger_mouse(double dcycs) +{ + int val_x; + int val_y; + + val_x = 0; + /* mous_phys_x is 0->560, convert that to 0-255 cyc */ + /* so, mult by 117 then divide by 256 */ + if(g_mouse_fifo_x[0] > BASE_MARGIN_LEFT) { + val_x = (g_mouse_fifo_x[0] - BASE_MARGIN_LEFT) * 117; + val_x = val_x >> 8; + } + + /* mous_phys_y is 0->384, convert that to 0-255 cyc */ + /* so, mult by 170 then divide by 256 (shift right by 8) */ + val_y = 0; + if(g_mouse_fifo_y[0] > BASE_MARGIN_TOP) { + val_y = ((g_mouse_fifo_y[0] - BASE_MARGIN_TOP) * 170) >> 8; + } + + if(val_x > 280) { + val_x = 280; + } + if(val_y > 280) { + val_y = 280; + } + + g_paddle_val[0] = val_x; + g_paddle_val[1] = val_y; + g_paddle_val[2] = 255; + g_paddle_val[3] = 255; + g_paddle_button[2] = 1; + g_paddle_button[3] = 1; +} + +int +read_paddles(int paddle, double dcycs) +{ + double trig_dcycs; + int val; + + /* This routine is called by any read to $c064-$c067 */ + if(g_swap_paddles) { + paddle = paddle ^ 1; + } + + paddle = paddle & 3; + + val = g_paddle_val[paddle]; + + if(g_invert_paddles) { + val = 255 - val; + } + + /* convert 0->255 into 0->2816.0 cycles (the paddle delay const) */ + trig_dcycs = g_paddle_trig_dcycs + (val * 11.0); + + if(dcycs < trig_dcycs) { + return 0x80; + } else { + return 0x00; + } +} + diff --git a/src/partls.c b/src/partls.c new file mode 100755 index 0000000..364ee94 --- /dev/null +++ b/src/partls.c @@ -0,0 +1,135 @@ + +#include "defc.h" +#include +#include +#include + + +#define BUF_SIZE 65536 +char buf[BUF_SIZE]; + +void +read_block(int fd, char *buf, int blk, int blk_size) +{ + int ret; + + ret = lseek(fd, blk * blk_size, SEEK_SET); + if(ret != blk * blk_size) { + printf("lseek: %d, errno: %d\n", ret, errno); + exit(1); + } + + ret = read(fd, buf, blk_size); + if(ret != blk_size) { + printf("ret: %d, errno: %d\n", ret, errno); + exit(1); + } +} + +int +main(int argc, char **argv) +{ + Driver_desc *driver_desc_ptr; + Part_map *part_map_ptr; + double dsize; + int fd; + int block_size; + word32 sig; + word32 map_blk_cnt; + word32 phys_part_start; + word32 part_blk_cnt; + word32 data_start; + word32 data_cnt; + int map_blocks; + int cur; + int long_form; + int last_arg; + int i; + + /* parse args */ + long_form = 0; + last_arg = 1; + for(i = 1; i < argc; i++) { + if(!strcmp("-l", argv[i])) { + long_form = 1; + } else { + last_arg = i; + break; + } + } + + + fd = open(argv[last_arg], O_RDONLY | O_BINARY, 0x1b6); + if(fd < 0) { + printf("open %s, ret: %d, errno:%d\n", argv[last_arg],fd,errno); + exit(1); + } + if(long_form) { + printf("fd: %d\n", fd); + } + + block_size = 512; + read_block(fd, buf, 0, block_size); + + driver_desc_ptr = (Driver_desc *)buf; + sig = GET_BE_WORD16(driver_desc_ptr->sig); + block_size = GET_BE_WORD16(driver_desc_ptr->blk_size); + if(long_form) { + printf("sig: %04x, blksize: %04x\n", sig, block_size); + } + if(block_size == 0) { + block_size = 512; + } + + if(sig == 0x4552 && block_size >= 0x200) { + if(long_form) { + printf("good!\n"); + } + } else { + printf("bad sig:%04x or block_size:%04x!\n", sig, block_size); + exit(1); + } + + map_blocks = 1; + cur = 0; + while(cur < map_blocks) { + read_block(fd, buf, cur + 1, block_size); + part_map_ptr = (Part_map *)buf; + sig = GET_BE_WORD16(part_map_ptr->sig); + map_blk_cnt = GET_BE_WORD32(part_map_ptr->map_blk_cnt); + phys_part_start = GET_BE_WORD32(part_map_ptr->phys_part_start); + part_blk_cnt = GET_BE_WORD32(part_map_ptr->part_blk_cnt); + data_start = GET_BE_WORD32(part_map_ptr->data_start); + data_cnt = GET_BE_WORD32(part_map_ptr->data_cnt); + + if(cur == 0) { + map_blocks = MIN(100, map_blk_cnt); + } + + if(long_form) { + printf("%2d: sig: %04x, map_blk_cnt: %d, " + "phys_part_start: %08x, part_blk_cnt: %08x\n", + cur, sig, map_blk_cnt, phys_part_start, + part_blk_cnt); + printf(" part_name: %s, part_type: %s\n", + part_map_ptr->part_name, + part_map_ptr->part_type); + printf(" data_start:%08x, data_cnt:%08x status:%08x\n", + GET_BE_WORD32(part_map_ptr->data_start), + GET_BE_WORD32(part_map_ptr->data_cnt), + GET_BE_WORD32(part_map_ptr->part_status)); + printf(" processor: %s\n", part_map_ptr->processor); + } else { + dsize = (double)GET_BE_WORD32(part_map_ptr->data_cnt); + printf("%2d:%-20s size=%6.2fMB type=%s\n", cur, + part_map_ptr->part_name, + (dsize/(1024.0*2.0)), + part_map_ptr->part_type); + } + + cur++; + } + + close(fd); + return 0; +} diff --git a/src/prodos.h b/src/prodos.h new file mode 100755 index 0000000..8ecca11 --- /dev/null +++ b/src/prodos.h @@ -0,0 +1,116 @@ +/****************************************************************/ +/* Apple //gs emulator */ +/* Copyright 1996 Kent Dickey */ +/* */ +/* This code may not be used in a commercial product */ +/* without prior written permission of the author. */ +/* */ +/* You may freely distribute this code. */ +/* */ +/* You can contact the author at kentd@cup.hp.com. */ +/* HP has nothing to do with this software. */ +/****************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_defc_h[] = "@(#)$Id: prodos.h,v 1.4 2002/11/19 07:49:31 kadickey Exp $"; +#endif + + +typedef struct l2byte_st L2byte; +struct l2byte_st { + byte low; + byte hi; +}; + +typedef struct l3byte_st L3byte; +struct l3byte_st { + byte low; + byte hi; + byte higher; +}; + +typedef L2byte Block; + +typedef struct pro_time_st Pro_time; +struct pro_time_st { + byte times[4]; +}; + +typedef struct file_entry_st File_entry; +struct file_entry_st { + byte storage_type_name_len; + byte file_name[15]; +/* 0x10 */ + byte file_type; + Block key_pointer; +/* 0x13 */ + L2byte blocks_used; +/* 0x15 */ + L3byte eof; +/* 0x18 */ + Pro_time creation_time; +/* 0x1c */ + byte version; + byte min_version; +/* 0x1e */ + byte access; +/* 0x1f */ + L2byte aux_type; +/* 0x21 */ + Pro_time last_mod; +/* 0x25 */ + Block header_pointer; +}; + +STRUCT(Vol_hdr) { +/* 0x4 */ + byte storage_type_name_len; +/* 0x5 */ + byte vol_name[15]; +/* 0x14 */ + byte res1[8]; +/* 0x1c */ + Pro_time creation_time; +/* 0x20 */ + byte version; + byte min_version; + byte access; + byte entry_length; +/* 0x24 */ + byte entries_per_block; + L2byte file_count; +/* 0x27 */ + Block bit_map; +/* 0x29 */ + L2byte total_blocks; +}; + +typedef struct directory_st Directory; +struct directory_st { + Block prev_blk; + Block next_blk; + File_entry file_entries[13]; +}; + +STRUCT(ProDisk) { + int fd; + int total_blocks; + int size_bitmap_blocks; + int disk_bytes_left; + + int bitmap_bytes; + int bitmap_cur_pos; + byte *bitmap_ptr; + + int file_open; + File_entry *file_ptr; + int dir_blk_num; + int ind_blk_num; + int master_ind_blk_num; + byte dir_blk_data[512]; + byte ind_blk_data[512]; + byte master_ind_blk_data[512]; +}; + + +#include "prodos_protos.h" diff --git a/src/prodos_protos.h b/src/prodos_protos.h new file mode 100755 index 0000000..bccdf8e --- /dev/null +++ b/src/prodos_protos.h @@ -0,0 +1,46 @@ +/****************************************************************/ +/* Apple //gs emulator */ +/* Copyright 1996 Kent Dickey */ +/* */ +/* This code may not be used in a commercial product */ +/* without prior written permission of the author. */ +/* */ +/* You may freely distribute this code. */ +/* */ +/* You can contact the author at kentd@cup.hp.com. */ +/* HP has nothing to do with this software. */ +/****************************************************************/ + +const char rcsid_prodos_protos_h[] = "@(#)$Id: prodos_protos.h,v 1.4 2002/11/19 07:49:31 kadickey Exp $"; + +/* to_pro.c */ +void flush_disk(ProDisk *disk); +void close_file(ProDisk *disk); +ProDisk *allocate_memdisk(char *out_name, int size); +void format_memdisk(ProDisk *ptr, char *name); +void disk_write_data(ProDisk *disk, int blk_num, byte *buf, int size); +void disk_read_data(ProDisk *disk, int blk_num, byte *buf, int size); +Directory *disk_read_dir(ProDisk *disk, int blk_num); +void disk_write_dir(ProDisk *disk, int blk_num); +void create_new_file(ProDisk *disk, int dir_block, int storage_type, + char *name, int file_type, word32 creation_time, int version, + int min_version, int access, int aux_type, word32 last_mod, word32 eof); +int pro_write_file(ProDisk *disk, byte *in_buf, int pos, int size); +int get_disk_block(ProDisk *disk, int pos, int create); +void get_new_ind_block(ProDisk *disk); +void write_ind_block(ProDisk *disk); +void get_new_master_ind_block(ProDisk *disk); +void write_master_ind_block(ProDisk *disk); +int find_next_free_block(ProDisk *disk); +void set_bitmap_used(byte *ptr, int i); +void set_bitmap_free(byte *ptr, int i); +void set_file_entry(File_entry *entry, int storage_type_name_len, + char *file_name, int file_type, int key_pointer, int blocks_used, + int eof, word32 creation, int version, int min_version, int access, + int aux_type, word32 last_mod, int header_pointer); +void set_l2byte(L2byte *ptr, int val); +void set_l3byte(L3byte *ptr, int val); +void set_pro_time(Pro_time *ptr, word32 val); +int get_l2byte(L2byte *ptr); +int get_l3byte(L3byte *ptr); +void inc_l2byte(L2byte *ptr); diff --git a/src/protos.h b/src/protos.h new file mode 100644 index 0000000..680ced2 --- /dev/null +++ b/src/protos.h @@ -0,0 +1,495 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_protos_h[] = "@(#)$KmKId: protos.h,v 1.173 2004-03-23 17:26:19-05 kentd Exp $"; +#endif + +/* xdriver.c and macdriver.c and windriver.c */ +void update_color_array(int col_num, int a2_color); +void set_border_color(int val); +void x_update_physical_colormap(void); +void show_xcolor_array(void); +void x_auto_repeat_on(int must); +void install_text_colormap(void); +void set_border_color(int val); +void draw_status(int line_num, const char *string1); +void xdriver_end(void); +void dev_video_init(void); +void x_update_color(int col_num, int red, int green, int blue, word32 rgb); +void redraw_border(void); +void check_input_events(void); +void x_redraw_status_lines(void); +void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height); +void x_push_done(); +void x_hide_pointer(int); +void x_get_kimage(Kimage *kimage_ptr); + +/* test65.c */ +void do_gen_test(int got_num, int base_seed); + + +/* engine.s and engine_c.c */ +void fixed_memory_ptrs_init(); +word32 get_itimer(void); + +word32 get_memory_c(word32 addr, int cycs); +word32 get_memory16_c(word32 addr, int cycs); +word32 get_memory24_c(word32 addr, int cycs); + +int get_memory_asm(word32 addr, int cycs); +int get_memory16_asm(word32 addr, int cycs); +int get_memory16_asm_fail(word32 addr, int cycs); +int get_memory_act_stub_asm(word32 addr, int cycs); +int get_memory16_act_stub_asm(word32 addr, int cycs); + +void set_memory_c(word32 addr, word32 val, int cycs); +void set_memory16_c(word32 addr, word32 val, int cycs); + +int enter_engine(Engine_reg *ptr); +void clr_halt_act(void); +void set_halt_act(int val); + +/* special scc_macdriver.c prototypes */ +int scc_serial_mac_init(int port); +void scc_serial_mac_change_params(int port); +void scc_serial_mac_fill_readbuf(int port, double dcycs); +void scc_serial_mac_empty_writebuf(int port); + +/* special scc_windriver.c prototypes */ +int scc_serial_win_init(int port); +void scc_serial_win_change_params(int port); +void scc_serial_win_fill_readbuf(int port, double dcycs); +void scc_serial_win_empty_writebuf(int port); + +/* special joystick_driver.c prototypes */ +void joystick_init(void); +void joystick_update(void); +void joystick_update_button(void); + + +/* END_HDR */ + +/* adb.c */ +void adb_init(void); +void adb_reset(void); +void adb_log(word32 addr, int val); +void show_adb_log(void); +void adb_error(void); +void adb_add_kbd_srq(void); +void adb_clear_kbd_srq(void); +void adb_add_data_int(void); +void adb_add_mouse_int(void); +void adb_clear_data_int(void); +void adb_clear_mouse_int(void); +void adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2); +void adb_send_1byte(word32 val); +void adb_response_packet(int num_bytes, word32 val); +void adb_kbd_reg0_data(int a2code, int is_up); +void adb_kbd_talk_reg0(void); +void adb_set_config(word32 val0, word32 val1, word32 val2); +void adb_set_new_mode(word32 val); +int adb_read_c026(void); +void adb_write_c026(int val); +void do_adb_cmd(void); +int adb_read_c027(void); +void adb_write_c027(int val); +int read_adb_ram(word32 addr); +void write_adb_ram(word32 addr, int val); +int update_mouse(int x, int y, int button_states, int buttons_valid); +int mouse_read_c024(double dcycs); +void adb_key_event(int a2code, int is_up); +word32 adb_read_c000(void); +word32 adb_access_c010(void); +word32 adb_read_c025(void); +int adb_is_cmd_key_down(void); +int adb_is_option_key_down(void); +void adb_increment_speed(void); +void adb_physical_key_update(int a2code, int is_up); +void adb_virtual_key_update(int a2code, int is_up); +void adb_kbd_repeat_off(void); + + +/* clock.c */ +double get_dtime(void); +int micro_sleep(double dtime); +void clk_bram_zero(void); +void clk_bram_set(int bram_num, int offset, int val); +void clk_setup_bram_version(void); +void clk_write_bram(FILE *fconf); +void update_cur_time(void); +void clock_update(void); +void clock_update_if_needed(void); +word32 clock_read_c033(void); +word32 clock_read_c034(void); +void clock_write_c033(word32 val); +void clock_write_c034(word32 val); +void do_clock_data(void); + + +/* compile_time.c */ + + +/* config.c */ +void config_init_menus(Cfg_menu *menuptr); +void config_init(void); +void cfg_exit(void); +void cfg_text_screen_dump(void); +void config_vbl_update(int doit_3_persec); +void config_parse_option(char *buf, int pos, int len, int line); +void config_parse_bram(char *buf, int pos, int len); +void config_parse_config_kegs_file(void); +Disk *cfg_get_dsk_from_slot_drive(int slot, int drive); +void config_generate_config_kegs_name(char *outstr, int maxlen, Disk *dsk, int with_extras); +void config_write_config_kegs_file(void); +void insert_disk(int slot, int drive, const char *name, int ejected, int force_size, const char *partition_name, int part_num); +void eject_named_disk(Disk *dsk, const char *name, const char *partition_name); +void eject_disk_by_num(int slot, int drive); +void eject_disk(Disk *dsk); +int cfg_get_fd_size(int fd); +int cfg_partition_read_block(int fd, void *buf, int blk, int blk_size); +int cfg_partition_find_by_name_or_num(int fd, const char *partnamestr, int part_num, Disk *dsk); +int cfg_partition_make_list(int fd); +int cfg_maybe_insert_disk(int slot, int drive, const char *namestr); +int cfg_stat(char *path, struct stat *sb); +void cfg_htab_vtab(int x, int y); +void cfg_home(void); +void cfg_cleol(void); +void cfg_putchar(int c); +void cfg_printf(const char *fmt, ...); +void cfg_print_num(int num, int max_len); +void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras); +void cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change); +void cfg_get_base_path(char *pathptr, const char *inptr, int go_up); +void cfg_file_init(void); +void cfg_free_alldirents(Cfg_listhdr *listhdrptr); +void cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, int size, int image_start, int part_num); +int cfg_dirent_sortfn(const void *obj1, const void *obj2); +int cfg_str_match(const char *str1, const char *str2, int len); +void cfg_file_readdir(const char *pathptr); +char *cfg_shorten_filename(const char *in_ptr, int maxlen); +void cfg_fix_topent(Cfg_listhdr *listhdrptr); +void cfg_file_draw(void); +void cfg_partition_selected(void); +void cfg_file_selected(void); +void cfg_file_handle_key(int key); +void config_control_panel(void); + + +/* dis.c */ +int get_num(void); +void debugger_help(void); +void do_debug_intfc(void); +word32 dis_get_memory_ptr(word32 addr); +void show_one_toolset(FILE *toolfile, int toolnum, word32 addr); +void show_toolset_tables(word32 a2bank, word32 addr); +void set_bp(word32 addr); +void show_bp(void); +void delete_bp(word32 addr); +void do_blank(void); +void do_go(void); +void do_step(void); +void xam_mem(int count); +void show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count); +int read_line(char *buf, int len); +void do_debug_list(void); +void load_roms(void); +void do_debug_unix(void); +void do_debug_load(void); +int do_dis(FILE *outfile, word32 kpc, int accsize, int xsize, int op_provided, word32 instr); +void show_line(FILE *outfile, word32 kaddr, word32 operand, int size, char *string); +void halt_printf(const char *fmt, ...); +void halt2_printf(const char *fmt, ...); + + +/* scc.c */ +void scc_init(void); +void scc_reset(void); +void scc_hard_reset_port(int port); +void scc_reset_port(int port); +void scc_regen_clocks(int port); +void scc_port_init(int port); +void scc_try_to_empty_writebuf(int port); +void scc_try_fill_readbuf(int port, double dcycs); +void scc_update(double dcycs); +void do_scc_event(int type, double dcycs); +void show_scc_state(void); +void scc_log(int regnum, word32 val, double dcycs); +void show_scc_log(void); +word32 scc_read_reg(int port, double dcycs); +void scc_write_reg(int port, word32 val, double dcycs); +void scc_maybe_br_event(int port, double dcycs); +void scc_evaluate_ints(int port); +void scc_maybe_rx_event(int port, double dcycs); +void scc_maybe_rx_int(int port, double dcycs); +void scc_clr_rx_int(int port); +void scc_handle_tx_event(int port, double dcycs); +void scc_maybe_tx_event(int port, double dcycs); +void scc_clr_tx_int(int port); +void scc_set_zerocnt_int(int port); +void scc_clr_zerocnt_int(int port); +void scc_add_to_readbuf(int port, word32 val, double dcycs); +void scc_add_to_writebuf(int port, word32 val, double dcycs); +word32 scc_read_data(int port, double dcycs); +void scc_write_data(int port, word32 val, double dcycs); + + +/* scc_socket_driver.c */ +void scc_socket_init(int port); +void scc_socket_change_params(int port); +void scc_accept_socket(int port); +void scc_socket_fill_readbuf(int port, double dcycs); +void scc_socket_empty_writebuf(int port); + + +/* scc_windriver.c */ + + +/* scc_macdriver.c */ + + +/* iwm.c */ +void iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525); +void iwm_init(void); +void iwm_reset(void); +void draw_iwm_status(int line, char *buf); +void iwm_flush_disk_to_unix(Disk *dsk); +void iwm_vbl_update(int doit_3_persec); +void iwm_show_stats(void); +void iwm_touch_switches(int loc, double dcycs); +void iwm_move_to_track(Disk *dsk, int new_track); +void iwm525_phase_change(int drive, int phase); +int iwm_read_status35(double dcycs); +void iwm_do_action35(double dcycs); +void iwm_set_apple35_sel(int newval); +int iwm_read_c0ec(double dcycs); +int read_iwm(int loc, double dcycs); +void write_iwm(int loc, int val, double dcycs); +int iwm_read_enable2(double dcycs); +int iwm_read_enable2_handshake(double dcycs); +void iwm_write_enable2(int val, double dcycs); +int iwm_read_data(Disk *dsk, int fast_disk_emul, double dcycs); +void iwm_write_data(Disk *dsk, word32 val, int fast_disk_emul, double dcycs); +void sector_to_partial_nib(byte *in, byte *nib_ptr); +int disk_unnib_4x4(Disk *dsk); +int iwm_denib_track525(Disk *dsk, Track *trk, int qtr_track, byte *outbuf); +int iwm_denib_track35(Disk *dsk, Track *trk, int qtr_track, byte *outbuf); +int disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf); +void show_hex_data(byte *buf, int count); +void disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size); +void disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, int nib_len); +void iwm_nibblize_track_nib525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track); +void iwm_nibblize_track_525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track); +void iwm_nibblize_track_35(Disk *dsk, Track *trk, byte *track_buf, int qtr_track); +void disk_4x4_nib_out(Disk *dsk, word32 val); +void disk_nib_out(Disk *dsk, byte val, int size); +void disk_nib_end_track(Disk *dsk); +void iwm_show_track(int slot_drive, int track); +void iwm_show_a_track(Track *trk); + + +/* joystick_driver.c */ + + +/* moremem.c */ +void fixup_brks(void); +void fixup_hires_on(void); +void fixup_bank0_2000_4000(void); +void fixup_bank0_0400_0800(void); +void fixup_any_bank_any_page(int start_page, int num_pages, byte *mem0rd, byte *mem0wr); +void fixup_intcx(void); +void fixup_wrdefram(int new_wrdefram); +void fixup_st80col(double dcycs); +void fixup_altzp(void); +void fixup_page2(double dcycs); +void fixup_ramrd(void); +void fixup_ramwrt(void); +void fixup_lcbank2(void); +void fixup_rdrom(void); +void set_statereg(double dcycs, int val); +void fixup_shadow_txt1(void); +void fixup_shadow_txt2(void); +void fixup_shadow_hires1(void); +void fixup_shadow_hires2(void); +void fixup_shadow_shr(void); +void fixup_shadow_iolc(void); +void update_shadow_reg(int val); +void fixup_shadow_all_banks(void); +void setup_pageinfo(void); +void show_bankptrs_bank0rdwr(void); +void show_bankptrs(int bnk); +void show_addr(byte *ptr); +int io_read(word32 loc, double *cyc_ptr); +void io_write(word32 loc, int val, double *cyc_ptr); +word32 get_lines_since_vbl(double dcycs); +int in_vblank(double dcycs); +int read_vid_counters(int loc, double dcycs); + + +/* paddles.c */ +void paddle_trigger(double dcycs); +void paddle_trigger_mouse(double dcycs); +int read_paddles(int paddle, double dcycs); + + +/* sim65816.c */ +void show_pc_log(void); +word32 toolbox_debug_4byte(word32 addr); +void toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr); +void show_toolbox_log(void); +word32 get_memory_io(word32 loc, double *cyc_ptr); +void set_memory_io(word32 loc, int val, double *cyc_ptr); +void show_regs_act(Engine_reg *eptr); +void show_regs(void); +void my_exit(int ret); +void do_reset(void); +void check_engine_asm_defines(void); +byte *memalloc_align(int size, int skip_amt); +void memory_ptr_init(void); +int kegsmain(int argc, char **argv); +void kegs_expand_path(char *out_ptr, const char *in_ptr, int maxlen); +void setup_kegs_file(char *outname, int maxlen, int ok_if_missing, const char **name_ptr); +void initialize_events(void); +void check_for_one_event_type(int type); +void add_event_entry(double dcycs, int type); +double remove_event_entry(int type); +void add_event_stop(double dcycs); +void add_event_doc(double dcycs, int osc); +void add_event_scc(double dcycs, int type); +void add_event_vbl(void); +void add_event_vid_upd(int line); +double remove_event_doc(int osc); +double remove_event_scc(int type); +void show_all_events(void); +void show_pmhz(void); +void setup_zip_speeds(void); +void run_prog(void); +void add_irq(void); +void remove_irq(void); +void take_irq(int is_it_brk); +void show_dtime_array(void); +void update_60hz(double dcycs, double dtime_now); +void do_vbl_int(void); +void do_scan_int(double dcycs, int line); +void check_scan_line_int(double dcycs, int cur_video_line); +void check_for_new_scan_int(double dcycs); +void init_reg(void); +void handle_action(word32 ret); +void do_break(word32 ret); +void do_cop(word32 ret); +void do_wdm(word32 arg); +void do_wai(void); +void do_stp(void); +void size_fail(int val, word32 v1, word32 v2); + + +/* smartport.c */ +void smartport_error(void); +void smartport_log(word32 start_addr, int cmd, int rts_addr, int cmd_list); +void do_c70d(word32 arg0); +void do_c70a(word32 arg0); +int do_read_c7(int unit_num, word32 buf, int blk); +int do_write_c7(int unit_num, word32 buf, int blk); +int do_format_c7(int unit_num); +void do_c700(word32 ret); + + +/* sound.c */ +void doc_log_rout(char *msg, int osc, double dsamps, int etc); +void show_doc_log(void); +void sound_init(void); +void sound_init_general(void); +void parent_sound_get_sample_rate(int read_fd); +void set_audio_rate(int rate); +void sound_reset(double dcycs); +void sound_shutdown(void); +void sound_update(double dcycs); +void open_sound_file(void); +void close_sound_file(void); +void check_for_range(word32 *addr, int num_samps, int offset); +void send_sound_to_file(word32 *addr, int shm_pos, int num_samps); +void send_sound(int real_samps, int size); +void show_c030_state(void); +void show_c030_samps(int *outptr, int num); +void sound_play(double dsamps); +void doc_handle_event(int osc, double dcycs); +void doc_sound_end(int osc, int can_repeat, double eff_dsamps, double dsamps); +void add_sound_irq(int osc); +void remove_sound_irq(int osc, int must); +void start_sound(int osc, double eff_dsamps, double dsamps); +void wave_end_estimate(int osc, double eff_dsamps, double dsamps); +void remove_sound_event(int osc); +void doc_write_ctl_reg(int osc, int val, double dsamps); +void doc_recalc_sound_parms(int osc, double eff_dcycs, double dsamps); +int doc_read_c030(double dcycs); +int doc_read_c03c(double dcycs); +int doc_read_c03d(double dcycs); +void doc_write_c03c(int val, double dcycs); +void doc_write_c03d(int val, double dcycs); +void doc_write_c03e(int val); +void doc_write_c03f(int val); +void doc_show_ensoniq_state(int osc); + + +/* sound_driver.c */ +void reliable_buf_write(word32 *shm_addr, int pos, int size); +void reliable_zero_write(int amt); +void child_sound_loop(int read_fd, int write_fd, word32 *shm_addr); +void child_sound_playit(word32 tmp); + + +/* video.c */ +void video_init(void); +void show_a2_line_stuff(void); +void video_reset(void); +void video_update(void); +int video_all_stat_to_line_stat(int line, int new_all_stat); +int *video_update_kimage_ptr(int line, int new_stat); +void change_a2vid_palette(int new_palette); +void check_a2vid_palette(void); +void change_display_mode(double dcycs); +void video_update_all_stat_through_line(int line); +void change_border_color(double dcycs, int val); +void update_border_info(void); +void update_border_line(int st_line_offset, int end_line_offset, int color); +void video_border_pixel_write(Kimage *kimage_ptr, int starty, int num_lines, word32 val, int st_off, int end_off); +void redraw_changed_text_40(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, int pixels_per_line); +void redraw_changed_text_80(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, int pixels_per_line); +void redraw_changed_gr(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_dbl_gr(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_hires(int start_offset, int start_line, int num_lines, int color, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_hires_bw(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_hires_color(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_dbl_hires(int start_offset, int start_line, int num_lines, int color, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_dbl_hires_bw(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line); +void redraw_changed_dbl_hires_color(int start_offset, int start_line, int num_lines, int reparse, byte *screen_data, int pixels_per_line); +int video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse); +void redraw_changed_super_hires(int start_offset, int start_line, int num_lines, int in_reparse, byte *screen_data); +void display_screen(void); +void video_update_event_line(int line); +void video_update_through_line(int line); +void video_refresh_lines(int st_line, int num_lines, int must_reparse); +void refresh_border(void); +void end_screen(void); +void read_a2_font(void); +void video_get_kimage(Kimage *kimage_ptr, int extend_info, int depth, int mdepth); +void video_get_kimages(void); +void video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx, int starty, int width, int height); +void video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, int right_pix); +void video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line, int end_line); +void video_push_border_sides(void); +void video_push_border_special(void); +void video_push_kimages(void); +void video_update_color_raw(int col_num, int a2_color); +void video_update_color_array(int col_num, int a2_color); +void video_update_colormap(void); +void video_update_status_line(int line, const char *string); +void video_show_debug_info(void); + diff --git a/src/protos_engine_c.h b/src/protos_engine_c.h new file mode 100644 index 0000000..195f3f3 --- /dev/null +++ b/src/protos_engine_c.h @@ -0,0 +1,39 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_protos_engine_c_h[] = "@(#)$KmKId: protos_engine_c.h,v 1.10 2004-01-10 15:50:02-05 kentd Exp $"; +#endif + +/* END_HDR */ + +/* engine_c.c */ +void check_breakpoints(word32 addr); +word32 get_memory8_io_stub(word32 addr, byte *stat, double *fcycs_ptr, double fplus_x_m1); +word32 get_memory16_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); +word32 get_memory24_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); +void set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, double fplus_x_m1); +void set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); +void set_memory24_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); +word32 get_memory_c(word32 addr, int cycs); +word32 get_memory16_c(word32 addr, int cycs); +word32 get_memory24_c(word32 addr, int cycs); +void set_memory_c(word32 addr, word32 val, int cycs); +void set_memory16_c(word32 addr, word32 val, int cycs); +void set_memory24_c(word32 addr, word32 val, int cycs); +word32 do_adc_sbc8(word32 in1, word32 in2, word32 psr, int sub); +word32 do_adc_sbc16(word32 in1, word32 in2, word32 psr, int sub); +void fixed_memory_ptrs_init(void); +word32 get_itimer(void); +void set_halt_act(int val); +void clr_halt_act(void); +word32 get_remaining_operands(word32 addr, word32 opcode, word32 psr, Fplus *fplus_ptr); +int enter_engine(Engine_reg *engine_ptr); + diff --git a/src/protos_macdriver.h b/src/protos_macdriver.h new file mode 100644 index 0000000..3fd840f --- /dev/null +++ b/src/protos_macdriver.h @@ -0,0 +1,40 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_protos_mac_h[] = "@(#)$KmKId: protos_macdriver.h,v 1.6 2004-03-23 17:27:31-05 kentd Exp $"; + +/* END_HDR */ + +/* macdriver.c */ +pascal OSStatus quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore); +void show_alert(const char *str1, const char *str2, const char *str3, int num); +pascal OSStatus my_cmd_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata); +void update_window(void); +void show_event(UInt32 event_class, UInt32 event_kind, int handled); +pascal OSStatus my_win_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata); +pascal OSStatus dummy_event_handler(EventHandlerCallRef call_ref, EventRef in_event, void *ignore); +void mac_update_modifiers(word32 state); +void mac_warp_mouse(void); +void check_input_events(void); +void temp_run_application_event_loop(void); +int main(int argc, char *argv[]); +void x_update_color(int col_num, int red, int green, int blue, word32 rgb); +void x_update_physical_colormap(void); +void show_xcolor_array(void); +void xdriver_end(void); +void x_get_kimage(Kimage *kimage_ptr); +void dev_video_init(void); +void x_redraw_status_lines(void); +void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height); +void x_push_done(void); +void x_auto_repeat_on(int must); +void x_auto_repeat_off(int must); +void x_hide_pointer(int do_hide); + diff --git a/src/protos_macsnd_driver.h b/src/protos_macsnd_driver.h new file mode 100644 index 0000000..73a79ee --- /dev/null +++ b/src/protos_macsnd_driver.h @@ -0,0 +1,20 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2003 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_protos_macsnd_driver_h[] = "@(#)$KmKId: protos_macsnd_driver.h,v 1.2 2003-11-19 19:57:02-05 kentd Exp $"; + +/* END_HDR */ + +/* macsnd_driver.c */ +void mac_snd_callback(SndChannelPtr snd_chan_ptr, SndCommand *in_sndcmd); +int mac_send_audio(byte *ptr, int in_size); +void child_sound_init_mac(void); +void macsnd_init(word32 *shmaddr); + diff --git a/src/protos_windriver.h b/src/protos_windriver.h new file mode 100644 index 0000000..c7f020f --- /dev/null +++ b/src/protos_windriver.h @@ -0,0 +1,36 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +// $KmKId: protos_windriver.h,v 1.4 2004-03-23 17:27:26-05 kentd Exp $ + +/* END_HDR */ + +/* windriver.c */ +int win_update_mouse(int x, int y, int button_states, int buttons_valid); +void win_event_mouse(WPARAM wParam, LPARAM lParam); +void win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags); +void win_event_quit(HWND hwnd); +void win_event_redraw(void); +LRESULT CALLBACK win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam); +int main(int argc, char **argv); +void check_input_events(void); +void x_update_color(int col_num, int red, int green, int blue, word32 rgb); +void x_update_physical_colormap(void); +void show_xcolor_array(void); +void xdriver_end(void); +void x_get_kimage(Kimage *kimage_ptr); +void dev_video_init(void); +void x_redraw_status_lines(void); +void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height); +void x_push_done(void); +void x_auto_repeat_on(int must); +void x_auto_repeat_off(int must); +void x_hide_pointer(int do_hide); + diff --git a/src/protos_xdriver.h b/src/protos_xdriver.h new file mode 100644 index 0000000..f43bf8d --- /dev/null +++ b/src/protos_xdriver.h @@ -0,0 +1,36 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_protos_x_h[] = "@(#)$KmKId: protos_xdriver.h,v 1.18 2002-11-19 03:10:38-05 kadickey Exp $"; + +/* END_HDR */ + +/* xdriver.c */ +int main(int argc, char **argv); +void x_update_physical_colormap(void); +void show_xcolor_array(void); +int my_error_handler(Display *display, XErrorEvent *ev); +void xdriver_end(void); +void show_colormap(char *str, Colormap cmap, int index1, int index2, int index3); +void dev_video_init(void); +Visual *x_try_find_visual(int depth, int screen_num, XVisualInfo **visual_list_ptr); +void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr); +int xhandle_shm_error(Display *display, XErrorEvent *event); +int get_shm(Kimage *kimage_ptr); +void get_ximage(Kimage *kimage_ptr); +void update_status_line(int line, const char *string); +void redraw_status_lines(void); +void check_input_events(void); +void handle_keysym(XEvent *xev_in); +int x_keysym_to_a2code(int keysym, int is_up); +void x_update_modifier_state(int state); +void x_auto_repeat_on(int must); +void x_auto_repeat_off(int must); + diff --git a/src/scc.c b/src/scc.c new file mode 100644 index 0000000..b21f5fd --- /dev/null +++ b/src/scc.c @@ -0,0 +1,1153 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_scc_c[] = "@(#)$KmKId: scc.c,v 1.38 2003-11-20 23:50:32-05 kentd Exp $"; + +#include "defc.h" + +extern int Verbose; +extern int g_code_yellow; +extern double g_cur_dcycs; +extern int g_raw_serial; +extern int g_serial_out_masking; + +/* my scc port 0 == channel A = slot 1 */ +/* port 1 == channel B = slot 2 */ + +#include "scc.h" +#define SCC_R14_DPLL_SOURCE_BRG 0x100 +#define SCC_R14_FM_MODE 0x200 + +#define SCC_DCYCS_PER_PCLK ((DCYCS_1_MHZ) / ((DCYCS_28_MHZ) /8)) +#define SCC_DCYCS_PER_XTAL ((DCYCS_1_MHZ) / 3686400.0) + +#define SCC_BR_EVENT 1 +#define SCC_TX_EVENT 2 +#define SCC_RX_EVENT 3 +#define SCC_MAKE_EVENT(port, a) (((a) << 1) + (port)) + +Scc scc_stat[2]; + +int g_baud_table[] = { + 110, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 +}; + +int g_scc_overflow = 0; + +void +scc_init() +{ + Scc *scc_ptr; + int i; + + for(i = 0; i < 2; i++) { + scc_ptr = &(scc_stat[i]); + scc_ptr->accfd = -1; + scc_ptr->rdwrfd = -1; + scc_ptr->state = 0; + scc_ptr->host_handle = 0; + scc_ptr->host_handle2 = 0; + scc_ptr->int_pending_rx = 0; + scc_ptr->int_pending_tx = 0; + scc_ptr->int_pending_zerocnt = 0; + scc_ptr->br_event_pending = 0; + scc_ptr->rx_event_pending = 0; + scc_ptr->tx_event_pending = 0; + scc_ptr->char_size = 8; + scc_ptr->baud_rate = 9600; + } + + scc_reset(); +} + +void +scc_reset() +{ + Scc *scc_ptr; + int i; + + for(i = 0; i < 2; i++) { + scc_ptr = &(scc_stat[i]); + + scc_ptr->port = i; + scc_ptr->mode = 0; + scc_ptr->reg_ptr = 0; + scc_ptr->in_rdptr = 0; + scc_ptr->in_wrptr = 0; + scc_ptr->out_rdptr = 0; + scc_ptr->out_wrptr = 0; + scc_ptr->wantint_rx = 0; + scc_ptr->wantint_tx = 0; + scc_ptr->wantint_zerocnt = 0; + scc_ptr->read_called_this_vbl = 0; + scc_ptr->write_called_this_vbl = 0; + scc_evaluate_ints(i); + scc_hard_reset_port(i); + } +} + +void +scc_hard_reset_port(int port) +{ + Scc *scc_ptr; + + scc_reset_port(port); + + scc_ptr = &(scc_stat[port]); + scc_ptr->reg[14] = 0; /* zero bottom two bits */ + scc_ptr->reg[13] = 0; + scc_ptr->reg[12] = 0; + scc_ptr->reg[11] = 0x08; + scc_ptr->reg[10] = 0; + scc_ptr->reg[7] = 0; + scc_ptr->reg[6] = 0; + scc_ptr->reg[5] = 0; + scc_ptr->reg[4] = 0x04; + scc_ptr->reg[3] = 0; + scc_ptr->reg[2] = 0; + scc_ptr->reg[1] = 0; + + /* HACK HACK: */ + scc_stat[0].reg[9] = 0; /* Clear all interrupts */ + + scc_evaluate_ints(port); + + scc_regen_clocks(port); +} + +void +scc_reset_port(int port) +{ + Scc *scc_ptr; + + scc_ptr = &(scc_stat[port]); + scc_ptr->reg[15] = 0xf8; + scc_ptr->reg[14] &= 0x03; /* 0 most (including >= 0x100) bits */ + scc_ptr->reg[10] = 0; + scc_ptr->reg[5] &= 0x65; /* leave tx bits and sdlc/crc bits */ + scc_ptr->reg[4] |= 0x04; /* Set async mode */ + scc_ptr->reg[3] &= 0xfe; /* clear receiver enable */ + scc_ptr->reg[1] &= 0xfe; /* clear ext int enable */ + + scc_ptr->br_is_zero = 0; + scc_ptr->tx_buf_empty = 1; + + scc_ptr->wantint_rx = 0; + scc_ptr->wantint_tx = 0; + scc_ptr->wantint_zerocnt = 0; + + scc_ptr->rx_queue_depth = 0; + + scc_evaluate_ints(port); + + scc_regen_clocks(port); + + scc_clr_tx_int(port); + scc_clr_rx_int(port); +} + +void +scc_regen_clocks(int port) +{ + Scc *scc_ptr; + double br_dcycs, tx_dcycs, rx_dcycs; + double rx_char_size, tx_char_size; + double clock_mult; + word32 reg4; + word32 reg14; + word32 reg11; + word32 br_const; + word32 baud; + word32 max_diff; + word32 diff; + int state; + int baud_entries; + int pos; + int i; + + /* Always do baud rate generator */ + scc_ptr = &(scc_stat[port]); + br_const = (scc_ptr->reg[13] << 8) + scc_ptr->reg[12]; + br_const += 2; /* counts down past 0 */ + + reg4 = scc_ptr->reg[4]; + clock_mult = 1.0; + switch((reg4 >> 6) & 3) { + case 0: /* x1 */ + clock_mult = 1.0; + break; + case 1: /* x16 */ + clock_mult = 16.0; + break; + case 2: /* x32 */ + clock_mult = 32.0; + break; + case 3: /* x64 */ + clock_mult = 64.0; + break; + } + + br_dcycs = 0.01; + reg14 = scc_ptr->reg[14]; + if(reg14 & 0x1) { + br_dcycs = SCC_DCYCS_PER_XTAL; + if(reg14 & 0x2) { + br_dcycs = SCC_DCYCS_PER_PCLK; + } + } + + br_dcycs = br_dcycs * (double)br_const; + + tx_dcycs = 1; + rx_dcycs = 1; + reg11 = scc_ptr->reg[11]; + if(((reg11 >> 3) & 3) == 2) { + tx_dcycs = 2.0 * br_dcycs * clock_mult; + } + if(((reg11 >> 5) & 3) == 2) { + rx_dcycs = 2.0 * br_dcycs * clock_mult; + } + + tx_char_size = 8.0; + switch((scc_ptr->reg[5] >> 5) & 0x3) { + case 0: // 5 bits + tx_char_size = 5.0; + break; + case 1: // 7 bits + tx_char_size = 7.0; + break; + case 2: // 6 bits + tx_char_size = 6.0; + break; + } + + scc_ptr->char_size = (int)tx_char_size; + + switch((scc_ptr->reg[4] >> 2) & 0x3) { + case 1: // 1 stop bit + tx_char_size += 2.0; // 1 stop + 1 start bit + break; + case 2: // 1.5 stop bit + tx_char_size += 2.5; // 1.5 stop + 1 start bit + break; + case 3: // 2 stop bits + tx_char_size += 3.0; // 2.0 stop + 1 start bit + break; + } + + if(scc_ptr->reg[4] & 1) { + // parity enabled + tx_char_size += 1.0; + } + + if(scc_ptr->reg[14] & 0x10) { + /* loopback mode, make it go faster...*/ + rx_char_size = 1.0; + tx_char_size = 1.0; + } + + rx_char_size = tx_char_size; /* HACK */ + + baud = (int)(DCYCS_1_MHZ / tx_dcycs); + max_diff = 5000000; + pos = 0; + baud_entries = sizeof(g_baud_table)/sizeof(g_baud_table[0]); + for(i = 0; i < baud_entries; i++) { + diff = abs(g_baud_table[i] - baud); + if(diff < max_diff) { + pos = i; + max_diff = diff; + } + } + + scc_ptr->baud_rate = g_baud_table[pos]; + + scc_ptr->br_dcycs = br_dcycs; + scc_ptr->tx_dcycs = tx_dcycs * tx_char_size; + scc_ptr->rx_dcycs = rx_dcycs * rx_char_size; + + state = scc_ptr->state; + if(state == 2) { + /* real serial ports */ +#ifdef MAC + scc_serial_mac_change_params(port); +#endif +#ifdef _WIN32 + scc_serial_win_change_params(port); +#endif + } else { + scc_socket_change_params(port); + } +} + +void +scc_port_init(int port) +{ + int state; + + state = 0; + if(g_raw_serial) { +#ifdef MAC + state = scc_serial_mac_init(port); +#endif +#ifdef _WIN32 + state = scc_serial_win_init(port); +#endif + } + + if(state <= 0) { + scc_socket_init(port); + } +} + +void +scc_try_to_empty_writebuf(int port) +{ + Scc *scc_ptr; + int state; + + scc_ptr = &(scc_stat[port]); + state = scc_ptr->state; + if(scc_ptr->write_called_this_vbl) { + return; + } + + scc_ptr->write_called_this_vbl = 1; + + if(state == 2) { +#if defined(MAC) + scc_serial_mac_empty_writebuf(port); +#endif +#if defined(_WIN32) + scc_serial_win_empty_writebuf(port); +#endif + } else if(state == 1) { + scc_socket_empty_writebuf(port); + } +} + +void +scc_try_fill_readbuf(int port, double dcycs) +{ + Scc *scc_ptr; + int state; + + scc_ptr = &(scc_stat[port]); + state = scc_ptr->state; +#if 0 + if(scc_ptr->read_called_this_vbl) { + return; + } +#endif + + scc_ptr->read_called_this_vbl = 1; + + if(state == 2) { +#if defined(MAC) + scc_serial_mac_fill_readbuf(port, dcycs); +#endif +#if defined(_WIN32) + scc_serial_win_fill_readbuf(port, dcycs); +#endif + } else if(state == 1) { + scc_socket_fill_readbuf(port, dcycs); + } +} + +void +scc_update(double dcycs) +{ + /* called each VBL update */ + scc_stat[0].write_called_this_vbl = 0; + scc_stat[1].write_called_this_vbl = 0; + scc_stat[0].read_called_this_vbl = 0; + scc_stat[1].read_called_this_vbl = 0; + + scc_try_to_empty_writebuf(0); + scc_try_to_empty_writebuf(1); + scc_try_fill_readbuf(0, dcycs); + scc_try_fill_readbuf(1, dcycs); + + scc_stat[0].write_called_this_vbl = 0; + scc_stat[1].write_called_this_vbl = 0; + scc_stat[0].read_called_this_vbl = 0; + scc_stat[1].read_called_this_vbl = 0; +} + +void +do_scc_event(int type, double dcycs) +{ + Scc *scc_ptr; + int port; + + port = type & 1; + type = (type >> 1); + + scc_ptr = &(scc_stat[port]); + if(type == SCC_BR_EVENT) { + /* baud rate generator counted down to 0 */ + scc_ptr->br_event_pending = 0; + scc_set_zerocnt_int(port); + scc_maybe_br_event(port, dcycs); + } else if(type == SCC_TX_EVENT) { + scc_ptr->tx_event_pending = 0; + scc_ptr->tx_buf_empty = 1; + scc_handle_tx_event(port, dcycs); + } else if(type == SCC_RX_EVENT) { + scc_ptr->rx_event_pending = 0; + scc_maybe_rx_event(port, dcycs); + } else { + halt_printf("do_scc_event: %08x!\n", type); + } + return; +} + +void +show_scc_state() +{ + Scc *scc_ptr; + int i, j; + + for(i = 0; i < 2; i++) { + scc_ptr = &(scc_stat[i]); + printf("SCC port: %d\n", i); + for(j = 0; j < 16; j += 4) { + printf("Reg %2d-%2d: %02x %02x %02x %02x\n", j, j+3, + scc_ptr->reg[j], scc_ptr->reg[j+1], + scc_ptr->reg[j+2], scc_ptr->reg[j+3]); + } + printf("in_rdptr: %04x, in_wr:%04x, out_rd:%04x, out_wr:%04x\n", + scc_ptr->in_rdptr, scc_ptr->in_wrptr, + scc_ptr->out_rdptr, scc_ptr->out_wrptr); + printf("rx_queue_depth: %d, queue: %02x, %02x, %02x, %02x\n", + scc_ptr->rx_queue_depth, scc_ptr->rx_queue[0], + scc_ptr->rx_queue[1], scc_ptr->rx_queue[2], + scc_ptr->rx_queue[3]); + printf("int_pendings: rx:%d, tx:%d, zc:%d\n", + scc_ptr->int_pending_rx, scc_ptr->int_pending_tx, + scc_ptr->int_pending_zerocnt); + printf("want_ints: rx:%d, tx:%d, zc:%d\n", + scc_ptr->wantint_rx, scc_ptr->wantint_tx, + scc_ptr->wantint_zerocnt); + printf("ev_pendings: rx:%d, tx:%d, br:%d\n", + scc_ptr->rx_event_pending, + scc_ptr->tx_event_pending, + scc_ptr->br_event_pending); + printf("br_dcycs: %f, tx_dcycs: %f, rx_dcycs: %f\n", + scc_ptr->br_dcycs, scc_ptr->tx_dcycs, + scc_ptr->rx_dcycs); + printf("char_size: %d, baud_rate: %d, mode: %d\n", + scc_ptr->char_size, scc_ptr->baud_rate, + scc_ptr->mode); + } + +} + +#define LEN_SCC_LOG 50 +STRUCT(Scc_log) { + int regnum; + word32 val; + double dcycs; +}; + +Scc_log g_scc_log[LEN_SCC_LOG]; +int g_scc_log_pos = 0; + +#define SCC_REGNUM(wr,port,reg) ((wr << 8) + (port << 4) + reg) + +void +scc_log(int regnum, word32 val, double dcycs) +{ + int pos; + + pos = g_scc_log_pos; + g_scc_log[pos].regnum = regnum; + g_scc_log[pos].val = val; + g_scc_log[pos].dcycs = dcycs; + pos++; + if(pos >= LEN_SCC_LOG) { + pos = 0; + } + g_scc_log_pos = pos; +} + +void +show_scc_log(void) +{ + double dcycs; + int regnum; + int pos; + int i; + + pos = g_scc_log_pos; + dcycs = g_cur_dcycs; + printf("SCC log pos: %d, cur dcycs:%f\n", pos, dcycs); + for(i = 0; i < LEN_SCC_LOG; i++) { + pos--; + if(pos < 0) { + pos = LEN_SCC_LOG - 1; + } + regnum = g_scc_log[pos].regnum; + printf("%d:%d: port:%d wr:%d reg: %d val:%02x at t:%f\n", + i, pos, (regnum >> 4) & 0xf, (regnum >> 8), + (regnum & 0xf), + g_scc_log[pos].val, + g_scc_log[pos].dcycs - dcycs); + } +} + +word32 +scc_read_reg(int port, double dcycs) +{ + Scc *scc_ptr; + word32 ret; + int regnum; + + scc_ptr = &(scc_stat[port]); + scc_ptr->mode = 0; + regnum = scc_ptr->reg_ptr; + + /* port 0 is channel A, port 1 is channel B */ + switch(regnum) { + case 0: + case 4: + ret = 0x68; /* 0x44 = no dcd, no cts,0x6c = dcd ok, cts ok*/ + if(scc_ptr->rx_queue_depth) { + ret |= 0x01; + } + if(scc_ptr->tx_buf_empty) { + ret |= 0x04; + } + if(scc_ptr->br_is_zero) { + ret |= 0x02; + } + //printf("Read scc[%d] stat: %f : %02x\n", port, dcycs, ret); + break; + case 1: + case 5: + /* HACK: residue codes not right */ + ret = 0x07; /* all sent */ + break; + case 2: + case 6: + if(port == 0) { + ret = scc_ptr->reg[2]; + } else { + + halt_printf("Read of RR2B...stopping\n"); + ret = 0; +#if 0 + ret = scc_stat[0].reg[2]; + wr9 = scc_stat[0].reg[9]; + for(i = 0; i < 8; i++) { + if(ZZZ){}; + } + if(wr9 & 0x10) { + /* wr9 status high */ + + } +#endif + } + break; + case 3: + case 7: + if(port == 0) { + ret = (scc_stat[1].int_pending_zerocnt) | + (scc_stat[1].int_pending_tx << 1) | + (scc_stat[1].int_pending_rx << 2) | + (scc_stat[0].int_pending_zerocnt << 3) | + (scc_stat[0].int_pending_tx << 4) | + (scc_stat[0].int_pending_rx << 5); + } else { + ret = 0; + } + break; + case 8: + ret = scc_read_data(port, dcycs); + break; + case 9: + case 13: + ret = scc_ptr->reg[13]; + break; + case 10: + case 14: + ret = 0; + break; + case 11: + case 15: + ret = scc_ptr->reg[15]; + break; + case 12: + ret = scc_ptr->reg[12]; + break; + default: + halt_printf("Tried reading c03%x with regnum: %d!\n", 8+port, + regnum); + ret = 0; + } + + scc_ptr->reg_ptr = 0; + scc_printf("Read c03%x, rr%d, ret: %02x\n", 8+port, regnum, ret); + if(regnum != 0 && regnum != 3) { + scc_log(SCC_REGNUM(0,port,regnum), ret, dcycs); + } + + return ret; +} + +void +scc_write_reg(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + word32 old_val; + word32 changed_bits; + int regnum; + int mode; + int tmp1; + + scc_ptr = &(scc_stat[port]); + regnum = scc_ptr->reg_ptr & 0xf; + mode = scc_ptr->mode; + + if(mode == 0) { + if((val & 0xf0) == 0) { + /* Set reg_ptr */ + scc_ptr->reg_ptr = val & 0xf; + regnum = 0; + scc_ptr->mode = 1; + } else { + scc_log(SCC_REGNUM(1,port,0), val, dcycs); + } + } else { + scc_ptr->reg_ptr = 0; + scc_ptr->mode = 0; + } + + if(regnum != 0) { + scc_log(SCC_REGNUM(1,port,regnum), val, dcycs); + } + + changed_bits = (scc_ptr->reg[regnum] ^ val) & 0xff; + + /* Set reg reg */ + switch(regnum) { + case 0: /* wr0 */ + tmp1 = (val >> 3) & 0x7; + switch(tmp1) { + case 0x0: + case 0x1: + break; + case 0x2: /* reset ext/status ints */ + /* should clear other ext ints */ + scc_clr_zerocnt_int(port); + break; + case 0x5: /* reset tx int pending */ + scc_clr_tx_int(port); + break; + case 0x6: /* reset rr1 bits */ + break; + case 0x7: /* reset highest pri int pending */ + if(scc_ptr->int_pending_rx) { + scc_clr_rx_int(port); + } else if(scc_ptr->int_pending_tx) { + scc_clr_tx_int(port); + } else if(scc_ptr->int_pending_zerocnt) { + scc_clr_zerocnt_int(port); + } + break; + case 0x4: /* enable int on next rx char */ + default: + halt_printf("Wr c03%x to wr0 of %02x, bad cmd cd:%x!\n", + 8+port, val, tmp1); + } + tmp1 = (val >> 6) & 0x3; + switch(tmp1) { + case 0x0: /* null code */ + break; + case 0x1: /* reset rx crc */ + case 0x2: /* reset tx crc */ + halt_printf("Wr c03%x to wr0 of %02x!\n", 8+port, val); + break; + case 0x3: /* reset tx underrun/eom latch */ + /* if no extern status pending, or being reset now */ + /* and tx disabled, ext int with tx underrun */ + /* ah, just do nothing */ + break; + } + return; + case 1: /* wr1 */ + /* proterm sets this == 0x10, which is int on all rx */ + scc_ptr->reg[regnum] = val; + return; + case 2: /* wr2 */ + /* All values do nothing, let 'em all through! */ + scc_ptr->reg[regnum] = val; + return; + case 3: /* wr3 */ + if((val & 0x1e) != 0x0) { + halt_printf("Wr c03%x to wr3 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 4: /* wr4 */ + if((val & 0x30) != 0x00 || (val & 0x0c) == 0) { + halt_printf("Wr c03%x to wr4 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 5: /* wr5 */ + if((val & 0x15) != 0x0) { + halt_printf("Wr c03%x to wr5 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + if(changed_bits & 0x60) { + scc_regen_clocks(port); + } + return; + case 6: /* wr6 */ + if(val != 0) { + halt_printf("Wr c03%x to wr6 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 7: /* wr7 */ + if(val != 0) { + halt_printf("Wr c03%x to wr7 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 8: /* wr8 */ + scc_write_data(port, val, dcycs); + return; + case 9: /* wr9 */ + if((val & 0xc0)) { + if(val & 0x80) { + scc_reset_port(0); + } + if(val & 0x40) { + scc_reset_port(1); + } + if((val & 0xc0) == 0xc0) { + scc_hard_reset_port(0); + scc_hard_reset_port(1); + } + } + if((val & 0x35) != 0x00) { + printf("Write c03%x to wr9 of %02x!\n", 8+port, val); + halt_printf("val & 0x35: %02x\n", (val & 0x35)); + } + old_val = scc_stat[0].reg[9]; + scc_stat[0].reg[regnum] = val; + scc_evaluate_ints(0); + scc_evaluate_ints(1); + return; + case 10: /* wr10 */ + if((val & 0xff) != 0x00) { + printf("Wr c03%x to wr10 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 11: /* wr11 */ + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 12: /* wr12 */ + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 13: /* wr13 */ + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 14: /* wr14 */ + old_val = scc_ptr->reg[regnum]; + val = val + (old_val & (~0xff)); + switch((val >> 5) & 0x7) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + break; + + case 0x4: /* DPLL source is BR gen */ + val |= SCC_R14_DPLL_SOURCE_BRG; + break; + default: + halt_printf("Wr c03%x to wr14 of %02x, bad dpll cd!\n", + 8+port, val); + } + if((val & 0x0c) != 0x0) { + halt_printf("Wr c03%x to wr14 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + scc_maybe_br_event(port, dcycs); + return; + case 15: /* wr15 */ + /* ignore all accesses since IIgs self test messes with it */ + if((val & 0xff) != 0x0) { + scc_printf("Write c03%x to wr15 of %02x!\n", 8+port, + val); + } + if((scc_stat[0].reg[9] & 0x8) && (val != 0)) { + printf("Write wr15:%02x and master int en = 1!\n",val); + /* set_halt(1); */ + } + scc_ptr->reg[regnum] = val; + scc_maybe_br_event(port, dcycs); + scc_evaluate_ints(port); + return; + default: + halt_printf("Wr c03%x to wr%d of %02x!\n", 8+port, regnum, val); + return; + } +} + +void +scc_maybe_br_event(int port, double dcycs) +{ + Scc *scc_ptr; + double br_dcycs; + + scc_ptr = &(scc_stat[port]); + + if(((scc_ptr->reg[14] & 0x01) == 0) || scc_ptr->br_event_pending) { + return; + } + /* also, if ext ints not enabled, don't do baud rate ints */ + if((scc_ptr->reg[15] & 0x02) == 0) { + return; + } + + br_dcycs = scc_ptr->br_dcycs; + if(br_dcycs < 1.0) { + halt_printf("br_dcycs: %f!\n", br_dcycs); + } + + scc_ptr->br_event_pending = 1; + add_event_scc(dcycs + br_dcycs, SCC_MAKE_EVENT(port, SCC_BR_EVENT)); +} + +void +scc_evaluate_ints(int port) +{ + Scc *scc_ptr; + int mie; + + scc_ptr = &(scc_stat[port]); + mie = scc_stat[0].reg[9] & 0x8; /* Master int en */ + + if(mie && scc_ptr->wantint_rx && !scc_ptr->int_pending_rx) { + scc_ptr->int_pending_rx = 1; + add_irq(); + } + if(scc_ptr->int_pending_rx && (!mie || !scc_ptr->wantint_rx)) { + scc_ptr->int_pending_rx = 0; + remove_irq(); + } + if(mie && scc_ptr->wantint_tx && !scc_ptr->int_pending_tx) { + scc_ptr->int_pending_tx = 1; + add_irq(); + } + if(scc_ptr->int_pending_tx && (!mie || !scc_ptr->wantint_tx)) { + scc_ptr->int_pending_tx = 0; + remove_irq(); + } + if(mie && scc_ptr->wantint_zerocnt && !scc_ptr->int_pending_zerocnt) { + scc_ptr->int_pending_zerocnt = 1; + add_irq(); + } + if(scc_ptr->int_pending_zerocnt && (!mie || !scc_ptr->wantint_zerocnt)){ + scc_ptr->int_pending_zerocnt = 0; + remove_irq(); + } +} + + +void +scc_maybe_rx_event(int port, double dcycs) +{ + Scc *scc_ptr; + double rx_dcycs; + int in_rdptr, in_wrptr; + int depth; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->rx_event_pending) { + /* one pending already, wait for the event to arrive */ + return; + } + + in_rdptr = scc_ptr->in_rdptr; + in_wrptr = scc_ptr->in_wrptr; + depth = scc_ptr->rx_queue_depth; + if((in_rdptr == in_wrptr) || (depth >= 3)) { + /* no more chars or no more space, just get out */ + return; + } + + if(depth < 0) { + depth = 0; + } + + /* pull char from in_rdptr into queue */ + scc_ptr->rx_queue[depth] = scc_ptr->in_buf[in_rdptr]; + scc_ptr->in_rdptr = (in_rdptr + 1) & (SCC_INBUF_SIZE - 1); + scc_ptr->rx_queue_depth = depth + 1; + scc_maybe_rx_int(port, dcycs); + rx_dcycs = scc_ptr->rx_dcycs; + scc_ptr->rx_event_pending = 1; + add_event_scc(dcycs + rx_dcycs, SCC_MAKE_EVENT(port, SCC_RX_EVENT)); +} + +void +scc_maybe_rx_int(int port, double dcycs) +{ + Scc *scc_ptr; + int depth; + int rx_int_mode; + + scc_ptr = &(scc_stat[port]); + + depth = scc_ptr->rx_queue_depth; + if(depth <= 0) { + /* no more chars, just get out */ + scc_clr_rx_int(port); + return; + } + rx_int_mode = (scc_ptr->reg[1] >> 3) & 0x3; + if(rx_int_mode == 1 || rx_int_mode == 2) { + scc_ptr->wantint_rx = 1; + } + scc_evaluate_ints(port); +} + +void +scc_clr_rx_int(int port) +{ + scc_stat[port].wantint_rx = 0; + scc_evaluate_ints(port); +} + +void +scc_handle_tx_event(int port, double dcycs) +{ + Scc *scc_ptr; + int tx_int_mode; + + scc_ptr = &(scc_stat[port]); + + /* nothing pending, see if ints on */ + tx_int_mode = (scc_ptr->reg[1] & 0x2); + if(tx_int_mode) { + scc_ptr->wantint_tx = 1; + } + scc_evaluate_ints(port); +} + +void +scc_maybe_tx_event(int port, double dcycs) +{ + Scc *scc_ptr; + double tx_dcycs; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->tx_event_pending) { + /* one pending already, tx_buf is full */ + scc_ptr->tx_buf_empty = 0; + } else { + /* nothing pending, see ints on */ + scc_evaluate_ints(port); + tx_dcycs = scc_ptr->tx_dcycs; + scc_ptr->tx_event_pending = 1; + add_event_scc(dcycs + tx_dcycs, + SCC_MAKE_EVENT(port, SCC_TX_EVENT)); + } +} + +void +scc_clr_tx_int(int port) +{ + scc_stat[port].wantint_tx = 0; + scc_evaluate_ints(port); +} + +void +scc_set_zerocnt_int(int port) +{ + Scc *scc_ptr; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->reg[15] & 0x2) { + scc_ptr->wantint_zerocnt = 1; + } + scc_evaluate_ints(port); +} + +void +scc_clr_zerocnt_int(int port) +{ + scc_stat[port].wantint_zerocnt = 0; + scc_evaluate_ints(port); +} + +void +scc_add_to_readbuf(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + int in_wrptr; + int in_wrptr_next; + int in_rdptr; + + scc_ptr = &(scc_stat[port]); + + in_wrptr = scc_ptr->in_wrptr; + in_rdptr = scc_ptr->in_rdptr; + in_wrptr_next = (in_wrptr + 1) & (SCC_INBUF_SIZE - 1); + if(in_wrptr_next != in_rdptr) { + scc_ptr->in_buf[in_wrptr] = val; + scc_ptr->in_wrptr = in_wrptr_next; + scc_printf("scc in port[%d] add char 0x%02x, %d,%d != %d\n", + scc_ptr->port, val, + in_wrptr, in_wrptr_next, in_rdptr); + g_scc_overflow = 0; + } else { + if(g_scc_overflow == 0) { + g_code_yellow++; + printf("scc inbuf overflow port %d\n", port); + } + g_scc_overflow = 1; + } + + scc_maybe_rx_event(port, dcycs); +} + +void +scc_add_to_writebuf(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + int out_wrptr; + int out_wrptr_next; + int out_rdptr; + + scc_ptr = &(scc_stat[port]); + + /* See if port initialized, if not, do so now */ + if(scc_ptr->state == 0) { + scc_port_init(port); + } + if(scc_ptr->state < 0) { + /* No working serial port, just toss it and go */ + return; + } + + if(!scc_ptr->tx_buf_empty) { + /* toss character! */ + printf("Tossing char\n"); + return; + } + + out_wrptr = scc_ptr->out_wrptr; + out_rdptr = scc_ptr->out_rdptr; + if(scc_ptr->tx_dcycs < 1.0) { + if(out_wrptr != out_rdptr) { + /* do just one char, then get out */ + printf("tx_dcycs < 1\n"); + return; + } + } + if(g_serial_out_masking) { + val = val & 0x7f; + } + + out_wrptr_next = (out_wrptr + 1) & (SCC_OUTBUF_SIZE - 1); + if(out_wrptr_next != out_rdptr) { + scc_ptr->out_buf[out_wrptr] = val; + scc_ptr->out_wrptr = out_wrptr_next; + scc_printf("scc wrbuf port %d had char 0x%02x added\n", + scc_ptr->port, val); + g_scc_overflow = 0; + } else { + if(g_scc_overflow == 0) { + g_code_yellow++; + printf("scc outbuf overflow port %d\n", port); + } + g_scc_overflow = 1; + } +} + +word32 +scc_read_data(int port, double dcycs) +{ + Scc *scc_ptr; + word32 ret; + int depth; + int i; + + scc_ptr = &(scc_stat[port]); + + scc_try_fill_readbuf(port, dcycs); + + depth = scc_ptr->rx_queue_depth; + + ret = 0; + if(depth != 0) { + ret = scc_ptr->rx_queue[0]; + for(i = 1; i < depth; i++) { + scc_ptr->rx_queue[i-1] = scc_ptr->rx_queue[i]; + } + scc_ptr->rx_queue_depth = depth - 1; + scc_maybe_rx_event(port, dcycs); + scc_maybe_rx_int(port, dcycs); + } + + scc_printf("SCC read %04x: ret %02x, depth:%d\n", 0xc03b-port, ret, + depth); + + scc_log(SCC_REGNUM(0,port,8), ret, dcycs); + + return ret; +} + + +void +scc_write_data(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + + scc_printf("SCC write %04x: %02x\n", 0xc03b-port, val); + scc_log(SCC_REGNUM(1,port,8), val, dcycs); + + scc_ptr = &(scc_stat[port]); + if(scc_ptr->reg[14] & 0x10) { + /* local loopback! */ + scc_add_to_readbuf(port, val, dcycs); + } else { + scc_add_to_writebuf(port, val, dcycs); + } + scc_try_to_empty_writebuf(port); + + scc_maybe_tx_event(port, dcycs); +} + diff --git a/src/scc.h b/src/scc.h new file mode 100644 index 0000000..ace256c --- /dev/null +++ b/src/scc.h @@ -0,0 +1,78 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_scc_h[] = "@(#)$KmKId: scc.h,v 1.12 2003-11-21 00:27:00-05 kentd Exp $"; +#endif + +#ifdef _WIN32 +# include +#else +# include +# include +#endif + +#if defined(HPUX) || defined(__linux__) || defined(SOLARIS) || defined(MAC) || defined(__MACH__) +# define SCC_SOCKETS +#endif + + +/* my scc port 0 == channel A, port 1 = channel B */ + +#define SCC_INBUF_SIZE 4096 /* must be a power of 2 */ +#define SCC_OUTBUF_SIZE 4096 /* must be a power of 2 */ + +STRUCT(Scc) { + int port; + int state; + int accfd; + int rdwrfd; + void *host_handle; + void *host_handle2; + int host_aux1; + int read_called_this_vbl; + int write_called_this_vbl; + + int mode; + int reg_ptr; + int reg[16]; + + int rx_queue_depth; + byte rx_queue[4]; + + int in_rdptr; + int in_wrptr; + byte in_buf[SCC_INBUF_SIZE]; + + int out_rdptr; + int out_wrptr; + byte out_buf[SCC_OUTBUF_SIZE]; + + int br_is_zero; + int tx_buf_empty; + int wantint_rx; + int wantint_tx; + int wantint_zerocnt; + int int_pending_rx; + int int_pending_tx; + int int_pending_zerocnt; + + double br_dcycs; + double tx_dcycs; + double rx_dcycs; + + int br_event_pending; + int rx_event_pending; + int tx_event_pending; + + int char_size; + int baud_rate; +}; + diff --git a/src/scc_macdriver.c b/src/scc_macdriver.c new file mode 100644 index 0000000..11c4184 --- /dev/null +++ b/src/scc_macdriver.c @@ -0,0 +1,211 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_scc_macdriver_c[] = "@(#)$KmKId: scc_macdriver.c,v 1.3 2003-11-03 01:52:49-05 kentd Exp $"; + +/* This file contains the Mac serial calls */ + +#include "defc.h" +#include "scc.h" + +#ifndef _WIN32 +# include +#endif + +extern Scc scc_stat[2]; +extern word32 g_c025_val; + +#ifdef MAC +int +scc_serial_mac_init(int port) +{ + char str_buf[1024]; + Scc *scc_ptr; + int state; + int fd; + + scc_ptr = &(scc_stat[port]); + + scc_ptr->state = 0; /* mark as uninitialized */ + + sprintf(&str_buf[0], "/dev/tty.USA19QW11P1.1"); + /* HACK: fix this... */ + + fd = open(&str_buf[0], O_RDWR | O_NONBLOCK); + + scc_ptr->host_handle = (void *)fd; + scc_ptr->host_handle2 = 0; + + printf("scc_serial_mac_init %d called, fd: %d\n", port, fd); + + if(fd < 0) { + scc_ptr->host_handle = (void *)-1; + return -1; + } + + scc_serial_mac_change_params(port); + + state = 2; /* raw serial */ + scc_ptr->state = state; + + return state; +} + +void +scc_serial_mac_change_params(int port) +{ + struct termios termios_buf; + Scc *scc_ptr; + int fd; + int csz; + int ret; + + scc_ptr = &(scc_stat[port]); + + fd = (int)scc_ptr->host_handle; + printf("scc_serial_mac_change_parms port: %d, fd: %d\n", port, fd); + if(fd <= 0) { + return; + } + + ret = tcgetattr(fd, &termios_buf); + if(ret != 0) { + printf("tcgetattr port%d ret: %d\n", port, ret); + } + +#if 1 + printf("baudrate: %d, iflag:%x, oflag:%x, cflag:%x, lflag:%x\n", + (int)termios_buf.c_ispeed, (int)termios_buf.c_iflag, + (int)termios_buf.c_oflag, (int)termios_buf.c_cflag, + (int)termios_buf.c_lflag); +#endif + + memset(&termios_buf, 0, sizeof(struct termios)); + cfmakeraw(&termios_buf); + cfsetspeed(&termios_buf, scc_ptr->baud_rate); + + csz = scc_ptr->char_size; + termios_buf.c_cflag = CREAD | CLOCAL; + termios_buf.c_cflag |= (csz == 5) ? CS5 : + (csz == 6) ? CS6 : + (csz == 7) ? CS7 : + CS8; + switch((scc_ptr->reg[4] >> 2) & 0x3) { + case 2: // 1.5 stop bits + termios_buf.c_cflag |= CSTOPB; /* no 1.5 stop bit setting.*/ + break; + case 3: // 2 stop bits + termios_buf.c_cflag |= CSTOPB; + break; + } + + switch((scc_ptr->reg[4]) & 0x3) { + case 1: // Odd parity + termios_buf.c_cflag |= (PARENB | PARODD); + break; + case 3: // Even parity + termios_buf.c_cflag |= PARENB; + break; + } + + /* always enabled DTR and RTS control */ + termios_buf.c_cflag |= CDTR_IFLOW | CRTS_IFLOW; + + printf("fd: %d, baudrate: %d, iflag:%x, oflag:%x, cflag:%x, lflag:%x\n", + fd, (int)termios_buf.c_ispeed, (int)termios_buf.c_iflag, + (int)termios_buf.c_oflag, (int)termios_buf.c_cflag, + (int)termios_buf.c_lflag); + ret = tcsetattr(fd, TCSANOW, &termios_buf); + if(ret != 0) { + printf("tcsetattr ret: %d\n", ret); + } +} + +void +scc_serial_mac_fill_readbuf(int port, double dcycs) +{ + byte tmp_buf[256]; + Scc *scc_ptr; + int fd; + int i; + int ret; + + scc_ptr = &(scc_stat[port]); + + fd = (int)scc_ptr->host_handle; + if(fd <= 0) { + return; + } + + /* Try reading some bytes */ + ret = read(fd, tmp_buf, 256); + + if(ret > 0) { + for(i = 0; i < ret; i++) { + scc_add_to_readbuf(port, tmp_buf[i], dcycs); + } + } + +} + +void +scc_serial_mac_empty_writebuf(int port) +{ + Scc *scc_ptr; + int fd; + int rdptr; + int wrptr; + int done; + int ret; + int len; + + scc_ptr = &(scc_stat[port]); + + fd = (int)scc_ptr->host_handle; + if(fd <= 0) { + return; + } + + /* Try writing some bytes */ + done = 0; + while(!done) { + rdptr = scc_ptr->out_rdptr; + wrptr = scc_ptr->out_wrptr; + if(rdptr == wrptr) { + //printf("...rdptr == wrptr\n"); + done = 1; + break; + } + len = wrptr - rdptr; + if(len < 0) { + len = SCC_OUTBUF_SIZE - rdptr; + } + if(len > 32) { + len = 32; + } + if(len <= 0) { + done = 1; + break; + } + ret = write(fd, &(scc_ptr->out_buf[rdptr]), len); + + if(ret <= 0) { + done = 1; + break; + } else { + rdptr = rdptr + ret; + if(rdptr >= SCC_OUTBUF_SIZE) { + rdptr = rdptr - SCC_OUTBUF_SIZE; + } + scc_ptr->out_rdptr = rdptr; + } + } +} +#endif /* MAC */ diff --git a/src/scc_socket_driver.c b/src/scc_socket_driver.c new file mode 100644 index 0000000..1decca5 --- /dev/null +++ b/src/scc_socket_driver.c @@ -0,0 +1,255 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_scc_socket_driver_c[] = "@(#)$KmKId: scc_socket_driver.c,v 1.4 2003-11-20 23:43:41-05 kentd Exp $"; + +/* This file contains the Unix socket calls */ + +#include "defc.h" +#include "scc.h" +#include + +extern Scc scc_stat[2]; + +void +scc_socket_init(int port) +{ +#ifdef SCC_SOCKETS + Scc *scc_ptr; + struct sockaddr_in sa_in; + int on; + int flags; + int ret; + int sockfd; + int inc; + + inc = 0; + + scc_ptr = &(scc_stat[port]); + + scc_ptr->state = -1; /* mark as failed for now */ + scc_ptr->host_aux1 = sizeof(struct sockaddr_in); + scc_ptr->host_handle = malloc(scc_ptr->host_aux1); + memset(scc_ptr->host_handle, 0, scc_ptr->host_aux1); + + while(1) { + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd < 0) { + printf("socket ret: %d, errno: %d\n", sockfd, errno); + return; + } + /* printf("socket ret: %d\n", sockfd); */ + + on = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)); + if(ret < 0) { + printf("setsockopt REUSEADDR ret: %d, err:%d\n", + ret, errno); + return; + } + + memset(&sa_in, 0, sizeof(sa_in)); + sa_in.sin_family = AF_INET; + sa_in.sin_port = htons(6501 + port + inc); + sa_in.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in)); + + if(ret < 0) { + printf("bind ret: %d, errno: %d\n", ret, errno); + inc++; + close(sockfd); + printf("Trying next port: %d\n", 6501 + port + inc); + if(inc >= 10) { + printf("Too many retries, quitting\n"); + return; + } + } else { + break; + } + } + + printf("SCC port %d is at unix port %d\n", port, 6501 + port + inc); + + ret = listen(sockfd, 1); + + flags = fcntl(sockfd, F_GETFL, 0); + if(flags == -1) { + printf("fcntl GETFL ret: %d, errno: %d\n", flags, errno); + return; + } + ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + if(ret == -1) { + printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno); + return; + } + + scc_ptr->accfd = sockfd; + scc_ptr->state = 1; /* successful socket */ +#endif /* SCC_SOCKETS */ +} + +void +scc_socket_change_params(int port) +{ +#ifdef SCC_SOCKETS +#endif +} + +void +scc_accept_socket(int port) +{ +#ifdef SCC_SOCKETS + Scc *scc_ptr; + int flags; + int rdwrfd; + int ret; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->rdwrfd <= 0) { + rdwrfd = accept(scc_ptr->accfd, scc_ptr->host_handle, + &(scc_ptr->host_aux1)); + if(rdwrfd < 0) { + return; + } + + /* For Linux, we need to set O_NONBLOCK on the rdwrfd */ + flags = fcntl(rdwrfd, F_GETFL, 0); + if(flags == -1) { + printf("fcntl GETFL ret: %d, errno: %d\n", flags,errno); + return; + } + ret = fcntl(rdwrfd, F_SETFL, flags | O_NONBLOCK); + if(ret == -1) { + printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno); + return; + } + + scc_ptr->rdwrfd = rdwrfd; + } +#endif +} + +void +scc_socket_fill_readbuf(int port, double dcycs) +{ +#ifdef SCC_SOCKETS + byte tmp_buf[256]; + Scc *scc_ptr; + int rdwrfd; + int i; + int ret; + + scc_ptr = &(scc_stat[port]); + + /* Accept socket if not already open */ + scc_accept_socket(port); + + rdwrfd = scc_ptr->rdwrfd; + if(rdwrfd < 0) { + return; + } + + /* Try reading some bytes */ + ret = read(rdwrfd, tmp_buf, 256); + if(ret > 0) { + for(i = 0; i < ret; i++) { + if(tmp_buf[i] == 0) { + /* Skip null chars */ + continue; + } + scc_add_to_readbuf(port, tmp_buf[i], dcycs); + } + } else if(ret == 0) { + /* assume socket close */ + close(rdwrfd); + scc_ptr->rdwrfd = -1; + } +#endif +} + +void +scc_socket_empty_writebuf(int port) +{ +#ifdef SCC_SOCKETS + struct sigaction newact, oldact; + Scc *scc_ptr; + int rdptr; + int wrptr; + int rdwrfd; + int done; + int ret; + int len; + + scc_ptr = &(scc_stat[port]); + + scc_accept_socket(port); + + rdwrfd = scc_ptr->rdwrfd; + if(rdwrfd < 0) { + return; + } + + /* Try writing some bytes */ + done = 0; + while(!done) { + rdptr = scc_ptr->out_rdptr; + wrptr = scc_ptr->out_wrptr; + if(rdptr == wrptr) { + done = 1; + break; + } + len = wrptr - rdptr; + if(len < 0) { + len = SCC_OUTBUF_SIZE - rdptr; + } + if(len > 32) { + len = 32; + } + if(len <= 0) { + done = 1; + break; + } + + /* ignore SIGPIPE around writes to the socket, so we can */ + /* catch a closed socket and prepare to re-accept a new */ + /* connection. Otherwise, SIGPIPE kills KEGS */ + sigemptyset(&newact.sa_mask); + newact.sa_handler = SIG_IGN; + newact.sa_flags = 0; + sigaction(SIGPIPE, &newact, &oldact); + + ret = write(rdwrfd, &(scc_ptr->out_buf[rdptr]), len); + + sigaction(SIGPIPE, &oldact, 0); + /* restore previous SIGPIPE behavior */ + + if(ret == 0) { + done = 1; /* give up for now */ + break; + } else if(ret < 0) { + /* assume socket is dead */ + close(rdwrfd); + scc_ptr->rdwrfd = -1; + done = 1; + break; + } else { + rdptr = rdptr + ret; + if(rdptr >= SCC_OUTBUF_SIZE) { + rdptr = rdptr - SCC_OUTBUF_SIZE; + } + scc_ptr->out_rdptr = rdptr; + } + } +#endif +} + diff --git a/src/scc_windriver.c b/src/scc_windriver.c new file mode 100644 index 0000000..57efd0b --- /dev/null +++ b/src/scc_windriver.c @@ -0,0 +1,252 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_scc_windriver_c[] = "@(#)$KmKId: scc_windriver.c,v 1.3 2003-09-20 15:05:15-04 kentd Exp $"; + +/* This file contains the Win32 COM1/COM2 calls */ + +#include "defc.h" +#include "scc.h" + +extern Scc scc_stat[2]; +extern word32 g_c025_val; + +#ifdef _WIN32 +int +scc_serial_win_init(int port) +{ + COMMTIMEOUTS commtimeouts; + char str_buf[8]; + Scc *scc_ptr; + HANDLE host_handle; + int state; + int ret; + + scc_ptr = &(scc_stat[port]); + + scc_ptr->state = 0; /* mark as failed */ + + sprintf(&str_buf[0], "COM%d", port+1); + + host_handle = CreateFile(&str_buf[0], GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + + scc_ptr->host_handle = host_handle; + scc_ptr->host_handle2 = malloc(sizeof(DCB)); + + printf("scc_socket_init %d called, host_handle: %p\n", port, + host_handle); + + if(host_handle == INVALID_HANDLE_VALUE) { + scc_ptr->host_handle = 0; + return 0; + } + + scc_serial_win_change_params(port); + + + commtimeouts.ReadIntervalTimeout = MAXDWORD; + commtimeouts.ReadTotalTimeoutMultiplier = 0; + commtimeouts.ReadTotalTimeoutConstant = 0; + commtimeouts.WriteTotalTimeoutMultiplier = 0; + commtimeouts.WriteTotalTimeoutConstant = 10; + ret = SetCommTimeouts(host_handle, &commtimeouts); + if(ret == 0) { + printf("setcommtimeout ret: %d\n", ret); + } + + state = 2; /* raw serial */ + scc_ptr->state = state; + + return state; +} + +void +scc_serial_win_change_params(int port) +{ + DCB *dcbptr; + HANDLE host_handle; + Scc *scc_ptr; + int ret; + + scc_ptr = &(scc_stat[port]); + + host_handle = scc_ptr->host_handle; + dcbptr = scc_ptr->host_handle2; + if(host_handle == 0) { + return; + } + + ret = GetCommState(host_handle, dcbptr); + if(ret == 0) { + printf("getcomm port%d ret: %d\n", port, ret); + } + +#if 1 + printf("dcb.baudrate: %d, bytesize:%d, stops:%d, parity:%d\n", + (int)dcbptr->BaudRate, (int)dcbptr->ByteSize, + (int)dcbptr->StopBits, (int)dcbptr->Parity); + printf("dcb.binary: %d, ctsflow: %d, dsrflow: %d, dtr: %d, dsr: %d\n", + (int)dcbptr->fBinary, + (int)dcbptr->fOutxCtsFlow, + (int)dcbptr->fOutxDsrFlow, + (int)dcbptr->fDtrControl, + (int)dcbptr->fDsrSensitivity); + printf("dcb.txonxoff:%d, outx:%d, inx: %d, null: %d, rts: %d\n", + (int)dcbptr->fTXContinueOnXoff, + (int)dcbptr->fOutX, + (int)dcbptr->fInX, + (int)dcbptr->fNull, + (int)dcbptr->fRtsControl); + printf("dcb.fAbortOnErr:%d, fParity:%d\n", (int)dcbptr->fAbortOnError, + (int)dcbptr->fParity); +#endif + + dcbptr->fAbortOnError = 0; + + dcbptr->BaudRate = scc_ptr->baud_rate; + dcbptr->ByteSize = scc_ptr->char_size; + dcbptr->StopBits = ONESTOPBIT; + switch((scc_ptr->reg[4] >> 2) & 0x3) { + case 2: // 1.5 stop bits + dcbptr->StopBits = ONE5STOPBITS; + break; + case 3: // 2 stop bits + dcbptr->StopBits = TWOSTOPBITS; + break; + } + + dcbptr->Parity = NOPARITY; + switch((scc_ptr->reg[4]) & 0x3) { + case 1: // Odd parity + dcbptr->Parity = ODDPARITY; + break; + case 3: // Even parity + dcbptr->Parity = EVENPARITY; + break; + } + + dcbptr->fNull = 0; + dcbptr->fDtrControl = DTR_CONTROL_ENABLE; + dcbptr->fDsrSensitivity = 0; + dcbptr->fOutxCtsFlow = 0; + dcbptr->fOutxDsrFlow = 0; + dcbptr->fParity = 0; + dcbptr->fInX = 0; + dcbptr->fOutX = 0; + dcbptr->fRtsControl = RTS_CONTROL_ENABLE; + + ret = SetCommState(host_handle, dcbptr); + if(ret == 0) { + printf("SetCommState ret: %d, new baud: %d\n", ret, + (int)dcbptr->BaudRate); + } +} + +void +scc_serial_win_fill_readbuf(int port, double dcycs) +{ + byte tmp_buf[256]; + Scc *scc_ptr; + HANDLE host_handle; + DWORD bytes_read; + int i; + int ret; + + scc_ptr = &(scc_stat[port]); + + host_handle = scc_ptr->host_handle; + if(host_handle == 0) { + return; + } + + /* Try reading some bytes */ + ret = ReadFile(host_handle, tmp_buf, 256, &bytes_read, NULL); + + if(ret == 0) { + printf("ReadFile ret 0\n"); + } + + if(ret && (bytes_read > 0)) { + for(i = 0; i < bytes_read; i++) { + scc_add_to_readbuf(port, tmp_buf[i], dcycs); + } + } + +} + +void +scc_serial_win_empty_writebuf(int port) +{ + Scc *scc_ptr; + HANDLE host_handle; + int rdptr; + int wrptr; + int done; + word32 err_code; + DWORD bytes_written; + int ret; + int len; + + scc_ptr = &(scc_stat[port]); + + //printf("win_empty_writebuf, host_handle: %d\n", scc_ptr->host_handle); + host_handle = scc_ptr->host_handle; + if(host_handle == 0) { + return; + } + + /* Try writing some bytes */ + done = 0; + while(!done) { + rdptr = scc_ptr->out_rdptr; + wrptr = scc_ptr->out_wrptr; + if(rdptr == wrptr) { + //printf("...rdptr == wrptr\n"); + done = 1; + break; + } + len = wrptr - rdptr; + if(len < 0) { + len = SCC_OUTBUF_SIZE - rdptr; + } + if(len > 32) { + len = 32; + } + if(len <= 0) { + done = 1; + break; + } + bytes_written = 1; + ret = WriteFile(host_handle, &(scc_ptr->out_buf[rdptr]), len, + &bytes_written, NULL); + printf("WriteFile ret: %d, bytes_written:%d, len:%d\n", ret, + (int)bytes_written, len); + + err_code = (word32)-1; + if(ret == 0) { + err_code = (word32)GetLastError(); + printf("WriteFile ret:0, err_code: %08x\n", err_code); + } + + if(ret == 0 || (bytes_written == 0)) { + done = 1; + break; + } else { + rdptr = rdptr + bytes_written; + if(rdptr >= SCC_OUTBUF_SIZE) { + rdptr = rdptr - SCC_OUTBUF_SIZE; + } + scc_ptr->out_rdptr = rdptr; + } + } +} + +#endif diff --git a/src/sim65816.c b/src/sim65816.c new file mode 100644 index 0000000..0f38d36 --- /dev/null +++ b/src/sim65816.c @@ -0,0 +1,2285 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_sim65816_c[] = "@(#)$KmKId: sim65816.c,v 1.346 2004-03-23 17:26:10-05 kentd Exp $"; + +#include + +#define INCLUDE_RCSID_C +#include "defc.h" +#undef INCLUDE_RCSID_C + +char g_argv0_path[256] = "./"; + +const char *g_kegs_default_paths[] = { "", "./", "${HOME}/", + "${0}/Contents/Resources/", "/usr/local/lib/", + "/usr/local/kegs/", "/usr/local/lib/kegs/", "/usr/share/kegs/", + "/usr/share/", "/var/lib/", "/usr/lib/", "/lib/", "/etc/", + "/etc/kegs/", "${0}/", 0 }; + +#define MAX_EVENTS 64 + +/* All EV_* must be less than 256, since upper bits reserved for other use */ +/* e.g., DOC_INT uses upper bits to encode oscillator */ +#define EV_60HZ 1 +#define EV_STOP 2 +#define EV_SCAN_INT 3 +#define EV_DOC_INT 4 +#define EV_VBL_INT 5 +#define EV_SCC 6 +#define EV_VID_UPD 7 + +extern int g_stepping; + +extern int statereg; +extern int g_cur_a2_stat; + +extern int wrdefram; +extern int int_crom[8]; + +extern int shadow_text; + +extern int shadow_reg; +extern int speed_fast; +extern word32 g_slot_motor_detect; + +extern int g_c023_val; +extern int c023_1sec_int_irq_pending; +extern int c023_scan_int_irq_pending; +extern int c041_en_25sec_ints; +extern int c041_en_vbl_ints; +extern int g_c046_val; +extern int c046_25sec_irq_pend; +extern int c046_vbl_irq_pending; +extern int g_zipgs_reg_c059; +extern int g_zipgs_reg_c05a; +extern int g_zipgs_reg_c05b; +extern int g_zipgs_unlock; + +extern int g_engine_c_mode; +extern int defs_instr_start_8; +extern int defs_instr_start_16; +extern int defs_instr_end_8; +extern int defs_instr_end_16; +extern int op_routs_start; +extern int op_routs_end; + +extern int updated_mod_latch; +extern int capslock_key_down; + +Engine_reg engine; +extern word32 table8[]; +extern word32 table16[]; + +extern byte doc_ram[]; + +extern int g_iwm_motor_on; +extern int g_fast_disk_emul; +extern int g_slow_525_emul_wr; +extern int g_apple35_sel; +extern int g_config_control_panel; + +extern int g_audio_enable; +extern int g_preferred_rate; + +void U_STACK_TRACE(); + +double g_fcycles_stop = 0.0; +int halt_sim = 0; +int enter_debug = 0; +int g_rom_version = 0; +int g_halt_on_bad_read = 0; +int g_ignore_bad_acc = 1; +int g_ignore_halts = 1; +int g_code_red = 0; +int g_code_yellow = 0; +int g_use_alib = 0; +int g_raw_serial = 1; +int g_serial_out_masking = 0; + +int g_config_iwm_vbl_count = 0; +const char g_kegs_version_str[] = "0.86"; + +#if 0 +const double g_drecip_cycles_in_16ms = (1.0/(DCYCS_IN_16MS)); +const double g_dcycles_in_16ms = DCYCS_IN_16MS; +#endif + +#define START_DCYCS (0.0) + +double g_last_vbl_dcycs = START_DCYCS; +double g_cur_dcycs = START_DCYCS; + +double g_last_vbl_dadjcycs = 0.0; +double g_dadjcycs = 0.0; + + +int g_wait_pending = 0; +int g_irq_pending = 0; + +int g_num_irq = 0; +int g_num_brk = 0; +int g_num_cop = 0; +int g_num_enter_engine = 0; +int g_io_amt = 0; +int g_engine_action = 0; +int g_engine_halt_event = 0; +int g_engine_scan_int = 0; +int g_engine_doc_int = 0; + +int g_testing = 0; +int g_testing_enabled = 0; + + +word32 stop_run_at; + +int g_25sec_cntr = 0; +int g_1sec_cntr = 0; + +double g_dnatcycs_1sec = 0.0; +word32 g_natcycs_lastvbl = 0; + +int Verbose = 0; +int Halt_on = 0; + +word32 g_mem_size_base = 256*1024; /* size of motherboard memory */ +word32 g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ +word32 g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ + +extern word32 slow_mem_changed[]; + +byte *g_slow_memory_ptr = 0; +byte *g_memory_ptr = 0; +byte *g_dummy_memory1_ptr = 0; +byte *g_rom_fc_ff_ptr = 0; +byte *g_rom_cards_ptr = 0; + +Page_info page_info_rd_wr[2*65536 + PAGE_INFO_PAD_SIZE]; + +int kbd_in_end = 0; +byte kbd_in_buf[LEN_KBD_BUF]; + + +#define PC_LOG_LEN (8*1024) + +Pc_log pc_log_array[PC_LOG_LEN + 2]; + +Pc_log *log_pc_ptr = &(pc_log_array[0]); +Pc_log *log_pc_start_ptr = &(pc_log_array[0]); +Pc_log *log_pc_end_ptr = &(pc_log_array[PC_LOG_LEN]); + + +void +show_pc_log() +{ + FILE *pcfile; + double dcycs; + double start_dcycs; + word32 instr; + word32 psr; + word32 acc, xreg, yreg; + word32 stack, direct; + word32 dbank; + word32 kpc; + int accsize, xsize; + int num; + int i; + + pcfile = fopen("pc_log_out", "wt"); + if(pcfile == 0) { + fprintf(stderr,"fopen failed...errno: %d\n", errno); + exit(2); + } +#if 0 + fprintf(pcfile, "current pc_log_ptr: %p, start: %p, end: %p\n", + log_pc_ptr, log_pc_start_ptr, log_pc_end_ptr); +#endif + + start_dcycs = log_pc_ptr->dcycs; + + for(i = 0; i < PC_LOG_LEN; i++) { + dbank = (log_pc_ptr->dbank_kpc >> 24) & 0xff; + kpc = log_pc_ptr->dbank_kpc & 0xffffff; + instr = log_pc_ptr->instr; + psr = (log_pc_ptr->psr_acc >> 16) & 0xffff;; + acc = log_pc_ptr->psr_acc & 0xffff;; + xreg = (log_pc_ptr->xreg_yreg >> 16) & 0xffff;; + yreg = log_pc_ptr->xreg_yreg & 0xffff;; + stack = (log_pc_ptr->stack_direct >> 16) & 0xffff;; + direct = log_pc_ptr->stack_direct & 0xffff;; + dcycs = log_pc_ptr->dcycs; + + num = log_pc_ptr - log_pc_start_ptr; + + accsize = 2; + xsize = 2; + if(psr & 0x20) { + accsize = 1; + } + if(psr & 0x10) { + xsize = 1; + } + + fprintf(pcfile, "%04x: A:%04x X:%04x Y:%04x P:%03x " + "S:%04x D:%04x B:%02x %9.2f ", i, + acc, xreg, yreg, psr, stack, direct, dbank, + (dcycs-start_dcycs)); + + do_dis(pcfile, kpc, accsize, xsize, 1, instr); + log_pc_ptr++; + if(log_pc_ptr >= log_pc_end_ptr) { + log_pc_ptr = log_pc_start_ptr; + } + } + + fclose(pcfile); +} + + +#define TOOLBOX_LOG_LEN 64 + +int g_toolbox_log_pos = 0; +word32 g_toolbox_log_array[TOOLBOX_LOG_LEN][8]; + +word32 +toolbox_debug_4byte(word32 addr) +{ + word32 part1, part2; + + /* If addr looks safe, use it */ + if(addr > 0xbffc) { + return (word32)-1; + } + + part1 = get_memory16_c(addr, 0); + part1 = (part1 >> 8) + ((part1 & 0xff) << 8); + part2 = get_memory16_c(addr+2, 0); + part2 = (part2 >> 8) + ((part2 & 0xff) << 8); + + return (part1 << 16) + part2; +} + +void +toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr) +{ + int pos; + + pos = g_toolbox_log_pos; + + stack += 9; + g_toolbox_log_array[pos][0] = g_last_vbl_dcycs + *cyc_ptr; + g_toolbox_log_array[pos][1] = stack+1; + g_toolbox_log_array[pos][2] = xreg; + g_toolbox_log_array[pos][3] = toolbox_debug_4byte(stack+1); + g_toolbox_log_array[pos][4] = toolbox_debug_4byte(stack+5); + g_toolbox_log_array[pos][5] = toolbox_debug_4byte(stack+9); + g_toolbox_log_array[pos][6] = toolbox_debug_4byte(stack+13); + g_toolbox_log_array[pos][7] = toolbox_debug_4byte(stack+17); + + pos++; + if(pos >= TOOLBOX_LOG_LEN) { + pos = 0; + } + + g_toolbox_log_pos = pos; +} + +void +show_toolbox_log() +{ + int pos; + int i; + + pos = g_toolbox_log_pos; + + for(i = TOOLBOX_LOG_LEN - 1; i >= 0; i--) { + printf("%2d:%2d: %08x %06x %04x: %08x %08x %08x %08x %08x\n", + i, pos, + g_toolbox_log_array[pos][0], + g_toolbox_log_array[pos][1], + g_toolbox_log_array[pos][2], + g_toolbox_log_array[pos][3], + g_toolbox_log_array[pos][4], + g_toolbox_log_array[pos][5], + g_toolbox_log_array[pos][6], + g_toolbox_log_array[pos][7]); + pos++; + if(pos >= TOOLBOX_LOG_LEN) { + pos = 0; + } + } +} + +#if 0 +/* get_memory_c is not used, get_memory_asm is, but this does what the */ +/* assembly language would do */ +word32 +get_memory_c(word32 loc, int diff_cycles) +{ + byte *addr; + word32 result; + int index; + +#ifdef CHECK_BREAKPOINTS + check_breakpoints_c(loc); +#endif + + index = loc >> 8; + result = page_info[index].rd; + if(result & BANK_IO_BIT) { + return get_memory_io(loc, diff_cycles); + } + + addr = (byte *)((result & 0xffffff00) + (loc & 0xff)); + + return *addr; +} +#endif + + +word32 +get_memory_io(word32 loc, double *cyc_ptr) +{ + int tmp; + + if(loc > 0xffffff) { + halt_printf("get_memory_io:%08x out of range==halt!\n", loc); + return 0; + } + + tmp = loc & 0xfef000; + if(tmp == 0xc000 || tmp == 0xe0c000) { + return(io_read(loc & 0xfff, cyc_ptr)); + } + + /* Else it's an illegal addr...skip if memory sizing */ + if(loc >= g_mem_size_total) { + if((loc & 0xfffe) == 0) { +#if 0 + printf("get_io assuming mem sizing, not halting\n"); +#endif + return 0; + } + } + + /* Skip reads to f80000 and f00000, just return 0 */ + if((loc & 0xf70000) == 0xf00000) { + return 0; + } + + if((loc & 0xff0000) == 0xef0000) { + /* DOC RAM */ + return (doc_ram[loc & 0xffff]); + } + + g_code_yellow++; + if(g_ignore_bad_acc) { + /* print no message, just get out. User doesn't want */ + /* to be bothered by buggy programs */ + return 0; + } + + printf("get_memory_io for addr: %06x\n", loc); + printf("stat for addr: %06x = %p\n", loc, + GET_PAGE_INFO_RD((loc >> 8) & 0xffff)); + set_halt(g_halt_on_bad_read); + + return 0; +} + +#if 0 +word32 +get_memory16_pieces(word32 loc, int diff_cycles) +{ + return(get_memory_c(loc, diff_cycles) + + (get_memory_c(loc+1, diff_cycles) << 8)); +} + +word32 +get_memory24(word32 loc, int diff_cycles) +{ + return(get_memory_c(loc, diff_cycles) + + (get_memory_c(loc+1, diff_cycles) << 8) + + (get_memory_c(loc+2, diff_cycles) << 16)); +} +#endif + +#if 0 +void +set_memory(word32 loc, int val, int diff_cycles) +{ + byte *ptr; + word32 new_addr; + word32 tmp; + word32 or_val; + int or_pos; + int old_slow_val; + +#ifdef CHECK_BREAKPOINTS + check_breakpoints_c(loc); +#endif + + tmp = GET_PAGE_INFO_WR((loc>>8) & 0xffff); + if(tmp & BANK_IO) { + set_memory_io(loc, val, diff_cycles); + return; + } + + if((loc & 0xfef000) == 0xe0c000) { + printf("set_memory_special: non-io for addr %08x, %02x, %d\n", + loc, val, diff_cycles); + halt_printf("tmp: %08x\n", tmp); + } + + ptr = (byte *)(tmp & (~0xff)); + + new_addr = loc & 0xffff; + old_slow_val = val; + + if(tmp & BANK_SHADOW) { + old_slow_val = g_slow_memory_ptr[new_addr]; + } else if(tmp & BANK_SHADOW2) { + new_addr += 0x10000; + old_slow_val = g_slow_memory_ptr[new_addr]; + } + + if(old_slow_val != val) { + g_slow_memory_ptr[new_addr] = val; + or_pos = (new_addr >> SHIFT_PER_CHANGE) & 0x1f; + or_val = DEP1(1, or_pos, 0); + if((new_addr >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE) { + printf("new_addr: %08x\n", new_addr); + exit(12); + } + slow_mem_changed[(new_addr & 0xffff) >> CHANGE_SHIFT] |= or_val; + } + + ptr[loc & 0xff] = val; + +} +#endif + +void +set_memory_io(word32 loc, int val, double *cyc_ptr) +{ + word32 tmp; + + tmp = loc & 0xfef000; + if(tmp == 0xc000 || tmp == 0xe0c000) { + io_write(loc, val, cyc_ptr); + return; + } + + /* Else it's an illegal addr */ + if(loc >= g_mem_size_total) { + if((loc & 0xfffe) == 0) { +#if 0 + printf("set_io assuming mem sizing, not halting\n"); +#endif + return; + } + } + + /* ignore writes to ROM */ + if((loc & 0xfc0000) == 0xfc0000) { + return; + } + + if((loc & 0xff0000) == 0xef0000) { + /* DOC RAM */ + doc_ram[loc & 0xffff] = val; + return; + } + + if(g_ignore_bad_acc) { + /* print no message, just get out. User doesn't want */ + /* to be bothered by buggy programs */ + return; + } + + if((loc & 0xffc000) == 0x00c000) { + printf("set_memory %06x = %02x, warning\n", loc, val); + return; + } + + halt_printf("set_memory %06x = %02x, stopping\n", loc, val); + + return; +} + + +#if 0 +void +check_breakpoints_c(word32 loc) +{ + int index; + int count; + int i; + + index = (loc & (MAX_BP_INDEX-1)); + count = breakpoints[index].count; + if(count) { + for(i = 0; i < count; i++) { + if(loc == breakpoints[index].addrs[i]) { + halt_printf("Write hit breakpoint %d!\n", i); + } + } + } +} +#endif + + +void +show_regs_act(Engine_reg *eptr) +{ + int tmp_acc, tmp_x, tmp_y, tmp_psw; + int kpc; + int direct_page, dbank; + int stack; + + kpc = eptr->kpc; + tmp_acc = eptr->acc; + direct_page = eptr->direct; + dbank = eptr->dbank; + stack = eptr->stack; + + tmp_x = eptr->xreg; + tmp_y = eptr->yreg; + + tmp_psw = eptr->psr; + + printf(" PC=%02x.%04x A=%04x X=%04x Y=%04x P=%03x", + kpc>>16, kpc & 0xffff ,tmp_acc,tmp_x,tmp_y,tmp_psw); + printf(" S=%04x D=%04x B=%02x,cyc:%.3f\n", stack, direct_page, + dbank, g_cur_dcycs); +} + +void +show_regs() +{ + show_regs_act(&engine); +} + +void +my_exit(int ret) +{ + end_screen(); + printf("exiting\n"); + exit(ret); +} + + +void +do_reset() +{ + int i; + + statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ + + wrdefram = 1; + for(i = 1; i < 7; i++) { + int_crom[i] = 0; + } + int_crom[7] = 0; + + engine.psr = (engine.psr | 0x134) & ~(0x08); + engine.stack = 0x100 + (engine.stack & 0xff); + engine.dbank = 0; + engine.direct = 0; + engine.xreg &= 0xff; + engine.yreg &= 0xff; + g_wait_pending = 0; + + + video_reset(); + adb_reset(); + iwm_reset(); + scc_reset(); + sound_reset(g_cur_dcycs); + setup_pageinfo(); + change_display_mode(g_cur_dcycs); + + engine.kpc = get_memory16_c(0x00fffc, 0); + + g_stepping = 0; + +} + +#define CHECK(start, var, value, var1, var2) \ + var2 = PTR2WORD(&(var)); \ + var1 = PTR2WORD((start)); \ + if((var2 - var1) != value) { \ + printf("CHECK: " #var " is 0x%x, but " #value " is 0x%x\n", \ + (var2 - var1), value); \ + exit(5); \ + } + +void +check_engine_asm_defines() +{ + Fplus fplus; + Fplus *fplusptr; + Pc_log pclog; + Pc_log *pcptr; + Engine_reg ereg; + Engine_reg *eptr; + word32 val1; + word32 val2; + + eptr = &ereg; + CHECK(eptr, eptr->fcycles, ENGINE_FCYCLES, val1, val2); + CHECK(eptr, eptr->fplus_ptr, ENGINE_FPLUS_PTR, val1, val2); + CHECK(eptr, eptr->acc, ENGINE_REG_ACC, val1, val2); + CHECK(eptr, eptr->xreg, ENGINE_REG_XREG, val1, val2); + CHECK(eptr, eptr->yreg, ENGINE_REG_YREG, val1, val2); + CHECK(eptr, eptr->stack, ENGINE_REG_STACK, val1, val2); + CHECK(eptr, eptr->dbank, ENGINE_REG_DBANK, val1, val2); + CHECK(eptr, eptr->direct, ENGINE_REG_DIRECT, val1, val2); + CHECK(eptr, eptr->psr, ENGINE_REG_PSR, val1, val2); + CHECK(eptr, eptr->kpc, ENGINE_REG_KPC, val1, val2); + + pcptr = &pclog; + CHECK(pcptr, pcptr->dbank_kpc, LOG_PC_DBANK_KPC, val1, val2); + CHECK(pcptr, pcptr->instr, LOG_PC_INSTR, val1, val2); + CHECK(pcptr, pcptr->psr_acc, LOG_PC_PSR_ACC, val1, val2); + CHECK(pcptr, pcptr->xreg_yreg, LOG_PC_XREG_YREG, val1, val2); + CHECK(pcptr, pcptr->stack_direct, LOG_PC_STACK_DIRECT, val1, val2); + if(LOG_PC_SIZE != sizeof(pclog)) { + printf("LOG_PC_SIZE: %d != sizeof=%d\n", LOG_PC_SIZE, + (int)sizeof(pclog)); + exit(2); + } + + fplusptr = &fplus; + CHECK(fplusptr, fplusptr->plus_1, FPLUS_PLUS_1, val1, val2); + CHECK(fplusptr, fplusptr->plus_2, FPLUS_PLUS_2, val1, val2); + CHECK(fplusptr, fplusptr->plus_3, FPLUS_PLUS_3, val1, val2); + CHECK(fplusptr, fplusptr->plus_x_minus_1, FPLUS_PLUS_X_M1, val1, val2); +} + +byte * +memalloc_align(int size, int skip_amt) +{ + byte *bptr; + word32 addr; + word32 offset; + + skip_amt = MAX(256, skip_amt); + bptr = malloc(size + skip_amt); + + addr = PTR2WORD(bptr) & 0xff; + + /* must align bptr to be 256-byte aligned */ + /* this code should work even if ptrs are > 32 bits */ + + offset = ((addr + skip_amt - 1) & (~0xff)) - addr; + + bptr += offset; + + /* Gilles Tschopp recommended zeroing memory, this is a good idea */ + memset(bptr, 0, size); + return bptr; +} + +void +memory_ptr_init() +{ + word32 mem_size; + + mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); + g_mem_size_total = mem_size; + g_memory_ptr = memalloc_align(mem_size, 3*1024); + + printf("RAM size is 0 - %06x (%.2fMB)\n", mem_size, + (double)mem_size/(1024.0*1024.0)); +} + +extern int g_screen_redraw_skip_amt; +extern int g_use_shmem; +extern int g_use_dhr140; +extern int g_use_bw_hires; + +char g_display_env[512]; +int g_force_depth = -1; +int g_screen_depth = 8; + + +int +kegsmain(int argc, char **argv) +{ + int skip_amt; + int diff; + int tmp1; + int i; + + /* parse args */ + for(i = 1; i < argc; i++) { + if(!strcmp("-badrd", argv[i])) { + printf("Halting on bad reads\n"); + g_halt_on_bad_read = 2; + } else if(!strcmp("-noignbadacc", argv[i])) { + printf("Not ignoring bad memory accesses\n"); + g_ignore_bad_acc = 0; + } else if(!strcmp("-noignhalt", argv[i])) { + printf("Not ignoring code red halts\n"); + g_ignore_halts = 0; + } else if(!strcmp("-test", argv[i])) { + printf("Allowing testing\n"); + g_testing_enabled = 1; + } else if(!strcmp("-hpdev", argv[i])) { + printf("Using /dev/audio\n"); + g_use_alib = 0; + } else if(!strcmp("-alib", argv[i])) { + printf("Using Aserver audio server\n"); + g_use_alib = 1; + } else if(!strcmp("-24", argv[i])) { + printf("Using 24-bit visual\n"); + g_force_depth = 24; + } else if(!strcmp("-16", argv[i])) { + printf("Using 16-bit visual\n"); + g_force_depth = 16; + } else if(!strcmp("-15", argv[i])) { + printf("Using 15-bit visual\n"); + g_force_depth = 15; + } else if(!strcmp("-mem", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + g_mem_size_exp = strtol(argv[i+1], 0, 0) & 0x00ff0000; + printf("Using %d as memory size\n", g_mem_size_exp); + i++; + } else if(!strcmp("-skip", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + skip_amt = strtol(argv[i+1], 0, 0); + printf("Using %d as skip_amt\n", skip_amt); + g_screen_redraw_skip_amt = skip_amt; + i++; + } else if(!strcmp("-audio", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Using %d as audio enable val\n", tmp1); + g_audio_enable = tmp1; + i++; + } else if(!strcmp("-arate", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Using %d as preferred audio rate\n", tmp1); + g_preferred_rate = tmp1; + i++; + } else if(!strcmp("-v", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Setting Verbose = 0x%03x\n", tmp1); + Verbose = tmp1; + i++; +#ifndef __NeXT__ + } else if(!strcmp("-display", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + printf("Using %s as display\n", argv[i+1]); + sprintf(g_display_env, "DISPLAY=%s", argv[i+1]); + putenv(&g_display_env[0]); + i++; +#endif + } else if(!strcmp("-noshm", argv[i])) { + printf("Not using X shared memory\n"); + g_use_shmem = 0; + } else if(!strcmp("-joystick", argv[i])) { + printf("Trying to use joystick\n"); + joystick_init(); + } else if(!strcmp("-dhr140", argv[i])) { + printf("Using simple dhires color map\n"); + g_use_dhr140 = 1; + } else if(!strcmp("-bw", argv[i])) { + printf("Forcing black-and-white hires modes\n"); + g_cur_a2_stat |= ALL_STAT_COLOR_C021; + g_use_bw_hires = 1; + } else { + printf("Bad option: %s\n", argv[i]); + exit(3); + } + } + + check_engine_asm_defines(); + fixed_memory_ptrs_init(); + + if(sizeof(word32) != 4) { + printf("sizeof(word32) = %d, must be 4!\n", + (int)sizeof(word32)); + exit(1); + } + + if(!g_engine_c_mode) { + diff = &defs_instr_end_8 - &defs_instr_start_8; + if(diff != 1) { + printf("defs_instr_end_8 - start is %d\n",diff); + exit(1); + } + + diff = &defs_instr_end_16 - &defs_instr_start_16; + if(diff != 1) { + printf("defs_instr_end_16 - start is %d\n", diff); + exit(1); + } + + diff = &op_routs_end - &op_routs_start; + if(diff != 1) { + printf("op_routs_end - start is %d\n", diff); + exit(1); + } + } + + iwm_init(); + config_init(); + + load_roms(); + memory_ptr_init(); + + init_reg(); + clear_halt(); + + initialize_events(); + + video_init(); + +#ifndef _WIN32 + //sleep(1); +#endif + sound_init(); + + scc_init(); + clk_setup_bram_version(); /* load_roms must be called first! */ + adb_init(); + + do_reset(); + g_stepping = 0; + do_go(); + + /* If we get here, we hit a breakpoint, call debug intfc */ + do_debug_intfc(); + + my_exit(0); + return 0; +} + +void +kegs_expand_path(char *out_ptr, const char *in_ptr, int maxlen) +{ + char name_buf[256]; + char *tmp_ptr; + int name_len; + int in_char; + int state; + + out_ptr[0] = 0; + + name_len = 0; + state = 0; + + /* See if in_ptr has ${} notation, replace with getenv or argv0 */ + while(maxlen > 0) { + in_char = *in_ptr++; + *out_ptr++ = in_char; + maxlen--; + if(state == 0) { + /* No $ seen yet, look for it */ + if(in_char == '$') { + state = 1; + } + } else if(state == 1) { + /* See if next char is '{' (dummy }) */ + if(in_char == '{') { /* add dummy } */ + state = 2; + name_len = 0; + out_ptr -= 2; + } else { + state = 0; + } + } else if(state == 2) { + /* fill name_buf ... dummy '{' */ + out_ptr--; + if(in_char == '}') { + name_buf[name_len] = 0; + + /* got token, now look it up */ + tmp_ptr = ""; + if(!strncmp("0", name_buf, 128)) { + /* Replace ${0} with g_argv0_path */ + tmp_ptr = &(g_argv0_path[0]); + } else { + tmp_ptr = getenv(name_buf); + if(tmp_ptr == 0) { + tmp_ptr = ""; + } + } + strncpy(out_ptr, tmp_ptr, maxlen); + out_ptr += strlen(tmp_ptr); + maxlen -= strlen(tmp_ptr); + state = 0; + } else { + name_buf[name_len++] = in_char; + } + } + if(in_char == 0) { + /* make sure its null terminated */ + *out_ptr++ = 0; + break; + } + } +} + +void +setup_kegs_file(char *outname, int maxlen, int ok_if_missing, + const char **name_ptr) +{ + char local_path[256]; + struct stat stat_buf; + const char **path_ptr; + const char **cur_name_ptr, **save_path_ptr; + int ret; + + outname[0] = 0; + + path_ptr = &g_kegs_default_paths[0]; + + save_path_ptr = path_ptr; + while(*path_ptr) { + kegs_expand_path(&(local_path[0]), *path_ptr, 250); + cur_name_ptr = name_ptr; + while(*cur_name_ptr) { + strcpy(outname, &(local_path[0])); + strncat(outname, *cur_name_ptr, 255-strlen(outname)); + if(!ok_if_missing) { + printf("Trying '%s'\n", outname); + } + ret = stat(outname, &stat_buf); + if(ret == 0) { + /* got it! */ + return; + } + cur_name_ptr++; + } + path_ptr++; + } + + if(ok_if_missing) { + outname[0] = 0; + return; + } + + /* couldn't find it, print out all the attempts */ + path_ptr = save_path_ptr; + printf("Could not find %s in any of these directories:\n", *name_ptr); + while(*path_ptr) { + printf(" %s\n", *path_ptr++); + } + system("pwd"); + + exit(2); +} + +Event g_event_list[MAX_EVENTS]; +Event g_event_free; +Event g_event_start; + +void +initialize_events() +{ + int i; + + for(i = 1; i < MAX_EVENTS; i++) { + g_event_list[i-1].next = &g_event_list[i]; + } + g_event_free.next = &g_event_list[0]; + g_event_list[MAX_EVENTS-1].next = 0; + + g_event_start.next = 0; + g_event_start.dcycs = 0.0; + + add_event_entry(DCYCS_IN_16MS, EV_60HZ); +} + +void +check_for_one_event_type(int type) +{ + Event *ptr; + int count; + int depth; + + count = 0; + depth = 0; + ptr = g_event_start.next; + while(ptr != 0) { + depth++; + if(ptr->type == type) { + count++; + if(count != 1) { + halt_printf("in check_for_1, type %d found at " + "depth: %d, count: %d, at %f\n", + type, depth, count, ptr->dcycs); + } + } + ptr = ptr->next; + } +} + + +void +add_event_entry(double dcycs, int type) +{ + Event *this_event; + Event *ptr, *prev_ptr; + int tmp_type; + int done; + + this_event = g_event_free.next; + if(this_event == 0) { + halt_printf("Out of queue entries!\n"); + show_all_events(); + return; + } + g_event_free.next = this_event->next; + + this_event->type = type; + + tmp_type = type & 0xff; + if((dcycs < 0.0) || (dcycs > (g_cur_dcycs + 50*1000*1000.0)) || + ((dcycs < g_cur_dcycs) && (tmp_type != EV_SCAN_INT))) { + halt_printf("add_event: dcycs: %f, type:%05x, cur_dcycs: %f!\n", + dcycs, type, g_cur_dcycs); + dcycs = g_cur_dcycs + 1000.0; + } + + ptr = g_event_start.next; + if(ptr && (dcycs < ptr->dcycs)) { + /* create event before next expected event */ + /* do this by setting HALT_EVENT */ + set_halt(HALT_EVENT); + } + + prev_ptr = &g_event_start; + ptr = g_event_start.next; + + done = 0; + while(!done) { + if(ptr == 0) { + this_event->next = ptr; + this_event->dcycs = dcycs; + prev_ptr->next = this_event; + return; + } else { + if(ptr->dcycs < dcycs) { + /* step across this guy */ + prev_ptr = ptr; + ptr = ptr->next; + } else { + /* go in front of this guy */ + this_event->dcycs = dcycs; + this_event->next = ptr; + prev_ptr->next = this_event; + return; + } + } + } +} + +extern int g_doc_saved_ctl; + +double +remove_event_entry(int type) +{ + Event *ptr, *prev_ptr; + Event *next_ptr; + + ptr = g_event_start.next; + prev_ptr = &g_event_start; + + while(ptr != 0) { + if((ptr->type & 0xffff) == type) { + /* got it, remove it */ + next_ptr = ptr->next; + prev_ptr->next = next_ptr; + + /* Add ptr to free list */ + ptr->next = g_event_free.next; + g_event_free.next = ptr; + + return ptr->dcycs; + } + prev_ptr = ptr; + ptr = ptr->next; + } + + halt_printf("remove event_entry: %08x, but not found!\n", type); + if((type & 0xff) == EV_DOC_INT) { + printf("DOC, g_doc_saved_ctl = %02x\n", g_doc_saved_ctl); + } +#ifdef HPUX + U_STACK_TRACE(); +#endif + show_all_events(); + + return 0.0; +} + +void +add_event_stop(double dcycs) +{ + add_event_entry(dcycs, EV_STOP); +} + +void +add_event_doc(double dcycs, int osc) +{ + if(dcycs < g_cur_dcycs) { + dcycs = g_cur_dcycs; +#if 0 + halt_printf("add_event_doc: dcycs: %f, cur_dcycs: %f\n", + dcycs, g_cur_dcycs); +#endif + } + + add_event_entry(dcycs, EV_DOC_INT + (osc << 8)); +} + +void +add_event_scc(double dcycs, int type) +{ + if(dcycs < g_cur_dcycs) { + dcycs = g_cur_dcycs; + } + + add_event_entry(dcycs, EV_SCC + (type << 8)); +} + +void +add_event_vbl() +{ + double dcycs; + + dcycs = g_last_vbl_dcycs + (DCYCS_IN_16MS * (192.0/262.0)); + add_event_entry(dcycs, EV_VBL_INT); +} + +void +add_event_vid_upd(int line) +{ + double dcycs; + + dcycs = g_last_vbl_dcycs + ((DCYCS_IN_16MS * line) / 262.0); + add_event_entry(dcycs, EV_VID_UPD + (line << 8)); +} + +double +remove_event_doc(int osc) +{ + return remove_event_entry(EV_DOC_INT + (osc << 8)); +} + +double +remove_event_scc(int type) +{ + return remove_event_entry(EV_SCC + (type << 8)); +} + +void +show_all_events() +{ + Event *ptr; + int count; + double dcycs; + + count = 0; + ptr = g_event_start.next; + while(ptr != 0) { + dcycs = ptr->dcycs; + printf("Event: %02x: type: %05x, dcycs: %f (%f)\n", + count, ptr->type, dcycs, dcycs - g_cur_dcycs); + ptr = ptr->next; + count++; + } + +} + +word32 g_vbl_count = 0; +int g_vbl_index_count = 0; +double dtime_array[60]; +double g_dadjcycs_array[60]; +double g_dtime_diff3_array[60]; +double g_dtime_this_vbl_array[60]; +double g_dtime_exp_array[60]; +double g_dtime_pmhz_array[60]; +double g_dtime_eff_pmhz_array[60]; +int g_limit_speed = 0; +double sim_time[60]; +double g_sim_sum = 0.0; + +double g_cur_sim_dtime = 0.0; +double g_projected_pmhz = 1.0; +double g_zip_pmhz = 8.0; +double g_sim_mhz = 100.0; +int g_line_ref_amt = 1; +int g_video_line_update_interval = 0; + +Fplus g_recip_projected_pmhz_slow; +Fplus g_recip_projected_pmhz_fast; +Fplus g_recip_projected_pmhz_zip; +Fplus g_recip_projected_pmhz_unl; + +Fplus *g_cur_fplus_ptr = 0; + +void +show_pmhz() +{ + printf("Pmhz: %f, plus_1: %f, fast: %d, limit: %d\n", + g_projected_pmhz, g_cur_fplus_ptr->plus_1, speed_fast, + g_limit_speed); + +} + +void +setup_zip_speeds() +{ + double frecip; + double fmhz; + int mult; + + mult = 16 - ((g_zipgs_reg_c05a >> 4) & 0xf); + // 16 = full speed, 1 = 1/16th speed + fmhz = (8.0 * mult) / 16.0; +#if 0 + if(mult == 16) { + /* increase full speed by 19% to make zipgs freq measuring */ + /* programs work correctly */ + fmhz = fmhz * 1.19; + } +#endif + frecip = 1.0 / fmhz; + g_zip_pmhz = fmhz; + g_recip_projected_pmhz_zip.plus_1 = frecip; + g_recip_projected_pmhz_zip.plus_2 = 2.0 * frecip; + g_recip_projected_pmhz_zip.plus_3 = 3.0 * frecip; + if(frecip >= 0.5) { + g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01; + } else { + g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01 - frecip; + } +} + +void +run_prog() +{ + Fplus *fplus_ptr; + Event *this_event; + Event *db1; + double dcycs; + double now_dtime; + double prev_dtime; + double prerun_fcycles; + double fspeed_mult; + double fcycles_stop; + word32 ret; + word32 zip_speed_0tof, zip_speed_0tof_new; + int zip_en, zip_follow_cps; + int type; + int motor_on; + int iwm_1; + int iwm_25; + int limit_speed; + int apple35_sel; + int fast, zip_speed, faster_than_28, unl_speed; + int this_type; + + fflush(stdout); + + g_cur_sim_dtime = 0.0; + + g_recip_projected_pmhz_slow.plus_1 = 1.0; + g_recip_projected_pmhz_slow.plus_2 = 2.0; + g_recip_projected_pmhz_slow.plus_3 = 3.0; + g_recip_projected_pmhz_slow.plus_x_minus_1 = 0.9; + + g_recip_projected_pmhz_fast.plus_1 = (1.0 / 2.5); + g_recip_projected_pmhz_fast.plus_2 = (2.0 / 2.5); + g_recip_projected_pmhz_fast.plus_3 = (3.0 / 2.5); + g_recip_projected_pmhz_fast.plus_x_minus_1 = (1.98 - (1.0/2.5)); + + zip_speed_0tof = g_zipgs_reg_c05a & 0xf0; + setup_zip_speeds(); + + if(g_cur_fplus_ptr == 0) { + g_recip_projected_pmhz_unl = g_recip_projected_pmhz_slow; + } + + while(1) { + fflush(stdout); + + if(g_irq_pending && !(engine.psr & 0x4)) { + irq_printf("taking an irq!\n"); + take_irq(0); + /* Interrupt! */ + } + + motor_on = g_iwm_motor_on; + limit_speed = g_limit_speed; + apple35_sel = g_apple35_sel; + zip_en = ((g_zipgs_reg_c05b & 0x10) == 0); + zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); + zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; + fast = speed_fast || (zip_en && !zip_follow_cps); + + if(zip_speed_0tof_new != zip_speed_0tof) { + zip_speed_0tof = zip_speed_0tof_new; + setup_zip_speeds(); + } + + iwm_1 = motor_on && !apple35_sel && + (g_slot_motor_detect & 0x4) && + (g_slow_525_emul_wr || !g_fast_disk_emul); + iwm_25 = (motor_on && apple35_sel) && !g_fast_disk_emul; + faster_than_28 = fast && (!iwm_1 && !iwm_25) && zip_en && + ((limit_speed == 0) || (limit_speed == 3)); + zip_speed = faster_than_28 && + ((zip_speed_0tof != 0) || (limit_speed == 3) || + (g_zipgs_unlock >= 4) ); + unl_speed = faster_than_28 && !zip_speed; + if(unl_speed) { + /* use unlimited speed */ + fspeed_mult = g_projected_pmhz; + fplus_ptr = &g_recip_projected_pmhz_unl; + } else if(zip_speed) { + fspeed_mult = g_zip_pmhz; + fplus_ptr = &g_recip_projected_pmhz_zip; + } else if(fast && !iwm_1 && !(limit_speed == 1)) { + fspeed_mult = 2.5; + fplus_ptr = &g_recip_projected_pmhz_fast; + } else { + /* else run slow */ + fspeed_mult = 1.0; + fplus_ptr = &g_recip_projected_pmhz_slow; + } + + g_cur_fplus_ptr = fplus_ptr; + engine.fplus_ptr = fplus_ptr; + + this_type = g_event_start.next->type; + + prerun_fcycles = g_cur_dcycs - g_last_vbl_dcycs; + engine.fcycles = prerun_fcycles; + fcycles_stop = (g_event_start.next->dcycs - g_last_vbl_dcycs) + + 0.001; + if(g_stepping) { + fcycles_stop = prerun_fcycles; + } + g_fcycles_stop = fcycles_stop; + +#if 0 + printf("Enter engine, fcycs: %f, stop: %f\n", + prerun_fcycles, fcycles_stop); + printf("g_cur_dcycs: %f, last_vbl_dcyc: %f\n", g_cur_dcycs, + g_last_vbl_dcycs); +#endif + + g_num_enter_engine++; + prev_dtime = get_dtime(); + + ret = enter_engine(&engine); + + now_dtime = get_dtime(); + + g_cur_sim_dtime += (now_dtime - prev_dtime); + + dcycs = g_last_vbl_dcycs + (double)(engine.fcycles); + + g_dadjcycs += (engine.fcycles - prerun_fcycles) * + fspeed_mult; + +#if 0 + printf("...back, engine.fcycles: %f, dcycs: %f\n", + (double)engine.fcycles, dcycs); +#endif + + g_cur_dcycs = dcycs; + + if(ret != 0) { + g_engine_action++; + handle_action(ret); + } + + if(halt_sim == HALT_EVENT) { + g_engine_halt_event++; + /* if we needed to stop to check for interrupts, */ + /* clear halt */ + halt_sim = 0; + } + +#if 0 + if(!g_testing && run_cycles < -2000000) { + halt_printf("run_cycles: %d, cycles: %d\n", run_cycles, + cycles); + printf("this_type: %05x\n", this_type); + printf("duff_cycles: %d\n", duff_cycles); + printf("start.next->rel_time: %d, type: %05x\n", + g_event_start.next->rel_time, + g_event_start.next->type); + } +#endif + + this_event = g_event_start.next; + while(dcycs >= this_event->dcycs) { + /* Pop this guy off of the queue */ + g_event_start.next = this_event->next; + + type = this_event->type; + this_event->next = g_event_free.next; + g_event_free.next = this_event; + switch(type & 0xff) { + case EV_60HZ: + update_60hz(dcycs, now_dtime); + break; + case EV_STOP: + printf("type: EV_STOP\n"); + printf("next: %p, dcycs: %f\n", + g_event_start.next, dcycs); + db1 = g_event_start.next; + halt_printf("next.dcycs: %f\n", db1->dcycs); + break; + case EV_SCAN_INT: + g_engine_scan_int++; + irq_printf("type: scan int\n"); + do_scan_int(dcycs, type >> 8); + break; + case EV_DOC_INT: + g_engine_doc_int++; + doc_handle_event(type >> 8, dcycs); + break; + case EV_VBL_INT: + do_vbl_int(); + break; + case EV_SCC: + do_scc_event(type >> 8, dcycs); + break; + case EV_VID_UPD: + video_update_event_line(type >> 8); + break; + default: + printf("Unknown event: %d!\n", type); + exit(3); + } + + this_event = g_event_start.next; + + } + + if(g_event_start.next == 0) { + halt_printf("ERROR...run_prog, event_start.n=0!\n"); + } + +#if 0 + if(!g_testing && g_event_start.next->rel_time > 2000000) { + printf("Z:start.next->rel_time: %d, duff_cycles: %d\n", + g_event_start.next->rel_time, duff_cycles); + halt_printf("Zrun_cycles:%d, cycles:%d\n", run_cycles, + cycles); + + show_all_events(); + } +#endif + + if(halt_sim != 0 && halt_sim != HALT_EVENT) { + break; + } + if(g_stepping) { + break; + } + if(g_config_control_panel) { + config_control_panel(); + } + } + + if(!g_testing) { + printf("leaving run_prog, halt_sim:%d\n", halt_sim); + } + + x_auto_repeat_on(0); +} + +void +add_irq() +{ + g_irq_pending++; + set_halt(HALT_EVENT); +} + +void +remove_irq() +{ + g_irq_pending--; + if(g_irq_pending < 0) { + halt_printf("remove_irq: g_irq_pending: %d\n", g_irq_pending); + } +} + +void +take_irq(int is_it_brk) +{ + word32 new_kpc; + word32 va; + + irq_printf("Taking irq, at: %02x/%04x, psw: %02x, dcycs: %f\n", + engine.kpc>>16, engine.kpc & 0xffff, engine.psr, + g_cur_dcycs); + + g_num_irq++; + if(g_wait_pending) { + /* step over WAI instruction */ + engine.kpc++; + g_wait_pending = 0; + } + + if(g_irq_pending < 0) { + halt_printf("g_irq_pending: %d!\n", g_irq_pending); + } + + if(engine.psr & 0x100) { + /* Emulation */ + set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xff) + 0x100; + + set_memory_c(engine.stack, engine.kpc & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xff) + 0x100; + + set_memory_c(engine.stack, + (engine.psr & 0xef)|(is_it_brk<<4),0); + /* Clear B bit in psr on stack */ + engine.stack = ((engine.stack -1) & 0xff) + 0x100; + + va = 0xfffffe; + if(shadow_reg & 0x40) { + /* I/O shadowing off...use ram locs */ + va = 0x00fffe; + } + + } else { + /* native */ + set_memory_c(engine.stack, (engine.kpc >> 16) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + set_memory_c(engine.stack, engine.kpc & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + set_memory_c(engine.stack, engine.psr & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + if(is_it_brk) { + /* break */ + va = 0xffffe6; + if(shadow_reg & 0x40) { + va = 0xffe6; + } + } else { + /* irq */ + va = 0xffffee; + if(shadow_reg & 0x40) { + va = 0xffee; + } + } + + } + + new_kpc = get_memory_c(va, 0); + new_kpc = new_kpc + (get_memory_c(va+1, 0) << 8); + + engine.psr = ((engine.psr & 0x1f3) | 0x4); + + engine.kpc = new_kpc; + HALT_ON(HALT_ON_IRQ, "Halting on IRQ\n"); + +} + +double g_dtime_last_vbl = 0.0; +double g_dtime_expected = (1.0/60.0); + +int g_scan_int_events = 0; + + + +void +show_dtime_array() +{ + double dfirst_time; + double first_total_cycs; + int i; + int pos; + + dfirst_time = 0.0; + first_total_cycs = 0.0; + + + for(i = 0; i < 60; i++) { + pos = (g_vbl_index_count + i) % 60; + printf("%2d:%2d dt:%.5f adjc:%9.1f this_vbl:%.6f " + "exp:%.5f p:%2.2f ep:%2.2f\n", + i, pos, + dtime_array[pos] - dfirst_time, + g_dadjcycs_array[pos] - first_total_cycs, + g_dtime_this_vbl_array[pos], + g_dtime_exp_array[pos] - dfirst_time, + g_dtime_pmhz_array[pos], + g_dtime_eff_pmhz_array[pos]); + dfirst_time = dtime_array[pos]; + first_total_cycs = g_dadjcycs_array[pos]; + } +} + +extern word32 g_cycs_in_40col; +extern word32 g_cycs_in_xredraw; +extern word32 g_cycs_in_check_input; +extern word32 g_cycs_in_refresh_line; +extern word32 g_cycs_in_refresh_ximage; +extern word32 g_cycs_in_io_read; +extern word32 g_cycs_in_sound1; +extern word32 g_cycs_in_sound2; +extern word32 g_cycs_in_sound3; +extern word32 g_cycs_in_sound4; +extern word32 g_cycs_in_start_sound; +extern word32 g_cycs_in_est_sound; +extern word32 g_refresh_bytes_xfer; + +extern int g_num_snd_plays; +extern int g_num_doc_events; +extern int g_num_start_sounds; +extern int g_num_scan_osc; +extern int g_num_recalc_snd_parms; +extern float g_fvoices; + +extern int g_doc_vol; +extern int g_a2vid_palette; + +extern int g_status_refresh_needed; + + +void +update_60hz(double dcycs, double dtime_now) +{ + register word32 end_time; + char status_buf[1024]; + char sim_mhz_buf[128]; + char total_mhz_buf[128]; + char *sim_mhz_ptr, *total_mhz_ptr; + char *code_str1, *code_str2, *sp_str; + double eff_pmhz; + double planned_dcycs; + double predicted_pmhz; + double recip_predicted_pmhz; + double dtime_this_vbl_sim; + double dtime_diff_1sec; + double dratio; + double dtime_till_expected; + double dtime_diff; + double dtime_this_vbl; + double dadjcycs_this_vbl; + double dadj_cycles_1sec; + double dtmp1, dtmp2, dtmp3, dtmp4, dtmp5; + double dnatcycs_1sec; + int tmp; + int doit_3_persec; + int cur_vbl_index; + int prev_vbl_index; + + g_vbl_count++; + + /* NOTE: this event is defined to occur before line 0 */ + /* It's actually happening at the start of the border for line (-1) */ + /* All other timings should be adjusted for this */ + + irq_printf("vbl_60hz: vbl: %d, dcycs: %f, last_vbl_dcycs: %f\n", + g_vbl_count, dcycs, g_last_vbl_dcycs); + + planned_dcycs = DCYCS_IN_16MS; + + g_last_vbl_dcycs = g_last_vbl_dcycs + planned_dcycs; + + add_event_entry(g_last_vbl_dcycs + planned_dcycs, EV_60HZ); + check_for_one_event_type(EV_60HZ); + + cur_vbl_index = g_vbl_index_count; + + /* figure out dtime spent running SIM, not all the overhead */ + dtime_this_vbl_sim = g_cur_sim_dtime; + g_cur_sim_dtime = 0.0; + g_sim_sum = g_sim_sum - sim_time[cur_vbl_index] + dtime_this_vbl_sim; + sim_time[cur_vbl_index] = dtime_this_vbl_sim; + + dadj_cycles_1sec = g_dadjcycs - g_dadjcycs_array[cur_vbl_index]; + + /* dtime_diff_1sec is dtime total spent over the last 60 ticks */ + dtime_diff_1sec = dtime_now - dtime_array[cur_vbl_index]; + + dtime_array[cur_vbl_index] = dtime_now; + g_dadjcycs_array[cur_vbl_index] = g_dadjcycs; + + prev_vbl_index = cur_vbl_index; + cur_vbl_index = prev_vbl_index + 1; + if(cur_vbl_index >= 60) { + cur_vbl_index = 0; + } + g_vbl_index_count = cur_vbl_index; + + GET_ITIMER(end_time); + g_dnatcycs_1sec += (double)(end_time - g_natcycs_lastvbl); + g_natcycs_lastvbl = end_time; + + if(prev_vbl_index == 0) { + if(g_sim_sum < (1.0/250.0)) { + sim_mhz_ptr = "???"; + g_sim_mhz = 250.0; + } else { + g_sim_mhz = (dadj_cycles_1sec / g_sim_sum) / + (1000.0*1000.0); + sprintf(sim_mhz_buf, "%6.2f", g_sim_mhz); + sim_mhz_ptr = sim_mhz_buf; + } + if(dtime_diff_1sec < (1.0/250.0)) { + total_mhz_ptr = "???"; + } else { + sprintf(total_mhz_buf, "%6.2f", + (dadj_cycles_1sec / dtime_diff_1sec) / + (1000000.0)); + total_mhz_ptr = total_mhz_buf; + } + + switch(g_limit_speed) { + case 1: sp_str = "1Mhz"; break; + case 2: sp_str = "2.8Mhz"; break; + case 3: sp_str = "8.0Mhz"; break; + default: sp_str = "Unlimited"; break; + } + + sprintf(status_buf, "dcycs:%9.1f sim MHz:%s " + "Eff MHz:%s, sec:%1.3f vol:%02x pal:%x, Limit:%s", + dcycs/(1000.0*1000.0), sim_mhz_ptr, total_mhz_ptr, + dtime_diff_1sec, g_doc_vol, g_a2vid_palette, + sp_str); + video_update_status_line(0, status_buf); + + if(g_video_line_update_interval == 0) { + if(g_sim_mhz > 12.0) { + /* just set video line_ref_amt to 1 */ + g_line_ref_amt = 1; + } else if(g_line_ref_amt == 1 && g_sim_mhz < 4.0) { + g_line_ref_amt = 8; + } + } else { + g_line_ref_amt = g_video_line_update_interval; + } + + if(g_dnatcycs_1sec < (1000.0*1000.0)) { + /* make it so large that all %'s become 0 */ + g_dnatcycs_1sec = 800.0*1000.0*1000.0*1000.0; + } + dnatcycs_1sec = g_dnatcycs_1sec / 100.0; /* eff mult by 100 */ + + dtmp2 = (double)(g_cycs_in_check_input) / dnatcycs_1sec; + dtmp3 = (double)(g_cycs_in_refresh_line) / dnatcycs_1sec; + dtmp4 = (double)(g_cycs_in_refresh_ximage) / dnatcycs_1sec; + sprintf(status_buf, "xfer:%08x, %5.1f ref_amt:%d " + "ch_in:%4.1f%% ref_l:%4.1f%% ref_x:%4.1f%%", + g_refresh_bytes_xfer, g_dnatcycs_1sec/(1000.0*1000.0), + g_line_ref_amt, dtmp2, dtmp3, dtmp4); + video_update_status_line(1, status_buf); + + sprintf(status_buf, "Ints:%3d I/O:%4dK BRK:%3d COP:%2d " + "Eng:%3d act:%3d hev:%3d esi:%3d edi:%3d", + g_num_irq, g_io_amt>>10, g_num_brk, g_num_cop, + g_num_enter_engine, g_engine_action, + g_engine_halt_event, g_engine_scan_int, + g_engine_doc_int); + video_update_status_line(2, status_buf); + + dtmp1 = (double)(g_cycs_in_sound1) / dnatcycs_1sec; + dtmp2 = (double)(g_cycs_in_sound2) / dnatcycs_1sec; + dtmp3 = (double)(g_cycs_in_sound3) / dnatcycs_1sec; + dtmp4 = (double)(g_cycs_in_start_sound) / dnatcycs_1sec; + dtmp5 = (double)(g_cycs_in_est_sound) / dnatcycs_1sec; + sprintf(status_buf, "snd1:%4.1f%%, 2:%4.1f%%, " + "3:%4.1f%%, st:%4.1f%% est:%4.1f%% %4.2f", + dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, g_fvoices); + video_update_status_line(3, status_buf); + + code_str1 = ""; + code_str2 = ""; + if(g_code_yellow) { + code_str1 = "Code: Yellow"; + code_str2 = "Emulated system state suspect, save work"; + } + if(g_code_red) { + code_str1 = "Code: RED"; + code_str2 = "Emulated system state probably corrupt"; + } + sprintf(status_buf, "snd_plays:%4d, doc_ev:%4d, st_snd:%4d " + "snd_parms: %4d %s", + g_num_snd_plays, g_num_doc_events, g_num_start_sounds, + g_num_recalc_snd_parms, code_str1); + video_update_status_line(4, status_buf); + + draw_iwm_status(5, status_buf); + + sprintf(status_buf, "KEGS v%-6s " + "Press F4 for Config Menu %s", + g_kegs_version_str, code_str2); + video_update_status_line(6, status_buf); + + g_status_refresh_needed = 1; + + g_num_irq = 0; + g_num_brk = 0; + g_num_cop = 0; + g_num_enter_engine = 0; + g_io_amt = 0; + g_engine_action = 0; + g_engine_halt_event = 0; + g_engine_scan_int = 0; + g_engine_doc_int = 0; + + g_cycs_in_40col = 0; + g_cycs_in_xredraw = 0; + g_cycs_in_check_input = 0; + g_cycs_in_refresh_line = 0; + g_cycs_in_refresh_ximage = 0; + g_cycs_in_io_read = 0; + g_cycs_in_sound1 = 0; + g_cycs_in_sound2 = 0; + g_cycs_in_sound3 = 0; + g_cycs_in_sound4 = 0; + g_cycs_in_start_sound = 0; + g_cycs_in_est_sound = 0; + g_dnatcycs_1sec = 0.0; + g_refresh_bytes_xfer = 0; + + g_num_snd_plays = 0; + g_num_doc_events = 0; + g_num_start_sounds = 0; + g_num_scan_osc = 0; + g_num_recalc_snd_parms = 0; + + g_fvoices = (float)0.0; + } + + dtime_this_vbl = dtime_now - g_dtime_last_vbl; + if(dtime_this_vbl < 0.001) { + dtime_this_vbl = 0.001; + } + + g_dtime_last_vbl = dtime_now; + + dadjcycs_this_vbl = g_dadjcycs - g_last_vbl_dadjcycs; + g_last_vbl_dadjcycs = g_dadjcycs; + + g_dtime_expected += (1.0/60.0); + + eff_pmhz = ((dadjcycs_this_vbl) / (dtime_this_vbl)) / + DCYCS_1_MHZ; + + /* using eff_pmhz, predict how many cycles can be run by */ + /* g_dtime_expected */ + + dtime_till_expected = g_dtime_expected - dtime_now; + + dratio = 60.0 * dtime_till_expected; + + predicted_pmhz = eff_pmhz * dratio; + + if(! (predicted_pmhz < (1.4 * g_projected_pmhz))) { + predicted_pmhz = 1.4 * g_projected_pmhz; + } + + if(! (predicted_pmhz > (0.7 * g_projected_pmhz))) { + predicted_pmhz = 0.7 * g_projected_pmhz; + } + + if(!(predicted_pmhz >= 1.0)) { + irq_printf("predicted: %f, setting to 1.0\n", predicted_pmhz); + predicted_pmhz = 1.0; + } + + if(!(predicted_pmhz < 250.0)) { + irq_printf("predicted: %f, setting to 250.0\n", predicted_pmhz); + predicted_pmhz = 250.0; + } + + recip_predicted_pmhz = 1.0/predicted_pmhz; + g_projected_pmhz = predicted_pmhz; + + g_recip_projected_pmhz_unl.plus_1 = 1.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_2 = 2.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_3 = 3.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_x_minus_1 = 1.01 - recip_predicted_pmhz; + + if(dtime_till_expected < -0.125) { + /* If we were way off, get back on track */ + /* this happens because our sim took much longer than */ + /* expected, so we're going to skip some VBL */ + irq_printf("adj1: dtexp:%f, dt_new:%f\n", + g_dtime_expected, dtime_now); + + dtime_diff = -dtime_till_expected; + + irq_printf("dtime_till_exp: %f, dtime_diff: %f, dcycs: %f\n", + dtime_till_expected, dtime_diff, dcycs); + + g_dtime_expected += dtime_diff; + } + + if(dtime_till_expected > (3/60.0)) { + /* we're running fast, usleep */ + micro_sleep(dtime_till_expected - (1/60.0)); + } + + g_dtime_this_vbl_array[prev_vbl_index] = dtime_this_vbl; + g_dtime_exp_array[prev_vbl_index] = g_dtime_expected; + g_dtime_pmhz_array[prev_vbl_index] = predicted_pmhz; + g_dtime_eff_pmhz_array[prev_vbl_index] = eff_pmhz; + + + if(c041_en_vbl_ints) { + add_event_vbl(); + } + + g_25sec_cntr++; + if(g_25sec_cntr >= 16) { + g_25sec_cntr = 0; + if(c041_en_25sec_ints && !c046_25sec_irq_pend) { + g_c046_val |= 0x10; + c046_25sec_irq_pend = 1; + add_irq(); + irq_printf("Setting c046 .25 sec int to 1, " + "g_irq_pend: %d\n", g_irq_pending); + } + } + + g_1sec_cntr++; + if(g_1sec_cntr >= 60) { + g_1sec_cntr = 0; + tmp = g_c023_val; + tmp |= 0x40; /* set 1sec int */ + if((tmp & 0x04) && !c023_1sec_int_irq_pending) { + c023_1sec_int_irq_pending = 1; + tmp |= 0x80; + add_irq(); + irq_printf("Setting c023 to %02x irq_pend: %d\n", + tmp, g_irq_pending); + } + g_c023_val = tmp; + } + + if(!g_scan_int_events) { + check_scan_line_int(dcycs, 0); + } + + doit_3_persec = 0; + if(g_config_iwm_vbl_count > 0) { + g_config_iwm_vbl_count--; + } else { + g_config_iwm_vbl_count = 20; + doit_3_persec = 1; + } + + iwm_vbl_update(doit_3_persec); + config_vbl_update(doit_3_persec); + + video_update(); + sound_update(dcycs); + clock_update(); + scc_update(dcycs); + joystick_update_button(); +} + +void +do_vbl_int() +{ + if(c041_en_vbl_ints && !c046_vbl_irq_pending) { + g_c046_val |= 0x08; + c046_vbl_irq_pending = 1; + add_irq(); + irq_printf("Setting c046 vbl_int_status to 1, irq_pend: %d\n", + g_irq_pending); + } +} + + +void +do_scan_int(double dcycs, int line) +{ + int c023_val; + g_scan_int_events = 0; + + c023_val = g_c023_val; + if(c023_val & 0x20) { + halt_printf("c023 scan_int and another on line %03x\n", line); + } + + /* make sure scan int is still enabled for this line */ + if(g_slow_memory_ptr[0x19d00 + line] & 0x40) { + /* valid interrupt, do it */ + c023_val |= 0xa0; /* vgc_int and scan_int */ + if((c023_val & 0x02) && !c023_scan_int_irq_pending) { + add_irq(); + c023_scan_int_irq_pending = 1; + irq_printf("Setting c023 to %02x, irq_pend: %d\n", + c023_val, g_irq_pending); + } + g_c023_val = c023_val; + HALT_ON(HALT_ON_SCAN_INT, "In do_scan_int\n"); + } else { + /* scan int bit cleared on scan line control byte */ + /* look for next line, if any */ + check_scan_line_int(dcycs, line+1); + } +} + + +void +check_scan_line_int(double dcycs, int cur_video_line) +{ + int delay; + int start; + int line; + int i; + /* Called during VBL interrupt phase */ + + if(!(g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { + return; + } + + if(g_c023_val & 0x20) { + /* don't check for any more */ + return; + } + + start = cur_video_line; + if(start < 0) { + halt_printf("check_scan_line_int: cur_video_line: %d\n", + cur_video_line); + start = 0; + } + + for(line = start; line < 200; line++) { + i = line; + + if(i < 0 || i >= 200) { + halt_printf("check_new_scan_int:i:%d, line:%d, st:%d\n", + i, line, start); + i = 0; + } + if(g_slow_memory_ptr[0x19d00+i] & 0x40) { + irq_printf("Adding scan_int for line %d\n", i); + delay = (DCYCS_IN_16MS/262.0) * ((double)line); + add_event_entry(g_last_vbl_dcycs + delay, EV_SCAN_INT + + (line << 8)); + g_scan_int_events = 1; + check_for_one_event_type(EV_SCAN_INT); + break; + } + } +} + +void +check_for_new_scan_int(double dcycs) +{ + int cur_video_line; + + cur_video_line = get_lines_since_vbl(dcycs) >> 8; + + check_scan_line_int(dcycs, cur_video_line); +} + +void +init_reg() +{ + engine.acc = 0; + engine.xreg = 0; + engine.yreg = 0; + engine.stack = 0x1ff; + engine.direct = 0; + engine.psr = 0x134; + +} + + +void +handle_action(word32 ret) +{ + int type; + + type = EXTRU(ret,3,4); + switch(type) { + case RET_BREAK: + do_break(ret & 0xff); + break; + case RET_COP: + do_cop(ret & 0xff); + break; +#if 0 + case RET_MVN: + do_mvn(ret & 0xffff); + break; +#endif + case RET_C700: + do_c700(ret); + break; + case RET_C70A: + do_c70a(ret); + break; + case RET_C70D: + do_c70d(ret); + break; +#if 0 + case RET_ADD_DEC_8: + do_add_dec_8(ret); + break; + case RET_ADD_DEC_16: + do_add_dec_16(ret); + break; +#endif + case RET_IRQ: + irq_printf("Special fast IRQ response. irq_pending: %x\n", + g_irq_pending); + break; + case RET_WDM: + do_wdm(ret & 0xff); + break; + default: + halt_printf("Unknown special action: %08x!\n", ret); + } + +} + +#if 0 +void +do_add_dec_8(word32 ret) +{ + halt_printf("do_add_dec_8 called, ret: %08x\n", ret); +} + +void +do_add_dec_16(word32 ret) +{ + halt_printf("do_add_dec_16 called, ret: %08x\n", ret); +} +#endif + +void +do_break(word32 ret) +{ + if(!g_testing) { + printf("I think I got a break, second byte: %02x!\n", ret); + printf("kpc: %06x\n", engine.kpc); + } + + halt_printf("do_break, kpc: %06x\n", engine.kpc); + enter_debug = 1; +} + +void +do_cop(word32 ret) +{ + halt_printf("COP instr %02x!\n", ret); + fflush(stdout); +} + +#if 0 +void +do_mvn(word32 banks) +{ + int src_bank, dest_bank; + int dest, src; + int num; + int i; + int val; + + halt_printf("In MVN...just quitting\n"); + return; + printf("MVN instr with %04x, cycles: %08x\n", banks, engine.cycles); + src_bank = banks >> 8; + dest_bank = banks & 0xff; + printf("psr: %03x\n", engine.psr); + if((engine.psr & 0x30) != 0) { + halt_printf("MVN in non-native mode unimplemented!\n"); + } + + dest = dest_bank << 16 | engine.yreg; + src = src_bank << 16 | engine.xreg; + num = engine.acc; + printf("Moving %08x+1 bytes from %08x to %08x\n", num, src, dest); + + for(i = 0; i <= num; i++) { + val = get_memory_c(src, 0); + set_memory_c(dest, val, 0); + src = (src_bank << 16) | ((src + 1) & 0xffff); + dest = (dest_bank << 16) | ((dest + 1) & 0xffff); + } + engine.dbank = dest_bank; + engine.acc = 0xffff; + engine.yreg = dest & 0xffff; + engine.xreg = src & 0xffff; + engine.kpc = (engine.kpc + 3); + printf("move done. db: %02x, acc: %04x, y: %04x, x: %04x, num: %08x\n", + engine.dbank, engine.acc, engine.yreg, engine.xreg, num); +} +#endif + +void +do_wdm(word32 arg) +{ + switch(arg) { + case 0x8d: /* Bouncin Ferno does WDM 8d */ + break; + default: + halt_printf("do_wdm: %02x!\n", arg); + } +} + +void +do_wai() +{ + halt_printf("do_wai!\n"); +} + +void +do_stp() +{ + halt_printf("Hit do_stp at addr: %06x\n", engine.kpc); +} + +void +size_fail(int val, word32 v1, word32 v2) +{ + halt_printf("Size failure, val: %08x, %08x %08x\n", val, v1, v2); +} + diff --git a/src/size_tab.h b/src/size_tab.h new file mode 100644 index 0000000..73c87d8 --- /dev/null +++ b/src/size_tab.h @@ -0,0 +1,274 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_S + .stringz "@(#)$KmKId: size_tab.h,v 1.13 2002-11-19 03:10:38-05 kadickey Exp $" +#else + + .word inst00_SYM+1 /* brk */ + .word inst01_SYM+1 /* ORA (Dloc,X) */ + .word inst02_SYM+1 /* COP */ + .word inst03_SYM+1 /* ORA Disp8,S */ + .word inst04_SYM+1 /* TSB Dloc */ + .word inst05_SYM+1 /* ORA Dloc */ + .word inst06_SYM+1 /* ASL Dloc */ + .word inst07_SYM+1 /* ORA [Dloc] */ + .word inst08_SYM+0 /* PHP */ + .word inst09_SYM+4 /* ORA #imm */ + .word inst0a_SYM+0 /* ASL a */ + .word inst0b_SYM+0 /* PHD */ + .word inst0c_SYM+2 /* TSB abs */ + .word inst0d_SYM+2 /* ORA abs */ + .word inst0e_SYM+2 /* ASL abs */ + .word inst0f_SYM+3 /* ORA long */ + .word inst10_SYM+1 /* BPL disp8 */ + .word inst11_SYM+1 /* ORA (),y */ + .word inst12_SYM+1 /* ORA () */ + .word inst13_SYM+1 /* ORA (disp8,s),y */ + .word inst14_SYM+1 /* TRB Dloc */ + .word inst15_SYM+1 /* ORA Dloc,x */ + .word inst16_SYM+1 /* ASL Dloc,x */ + .word inst17_SYM+1 /* ORA [],y */ + .word inst18_SYM+0 /* clc */ + .word inst19_SYM+2 /* ORA abs,y */ + .word inst1a_SYM+0 /* INC a */ + .word inst1b_SYM+0 /* TCS */ + .word inst1c_SYM+2 /* TRB Abs */ + .word inst1d_SYM+2 /* ORA Abs,X */ + .word inst1e_SYM+2 /* ASL abs,x */ + .word inst1f_SYM+3 /* ORA Long,x */ + .word inst20_SYM+2 /* JSR abs */ + .word inst21_SYM+1 /* AND (Dloc,X) */ + .word inst22_SYM+3 /* JSL Abslong */ + .word inst23_SYM+1 /* AND Disp8,S */ + .word inst24_SYM+1 /* BIT Dloc */ + .word inst25_SYM+1 /* AND Dloc */ + .word inst26_SYM+1 /* ROL Dloc */ + .word inst27_SYM+1 /* AND [Dloc] */ + .word inst28_SYM+0 /* PLP */ + .word inst29_SYM+4 /* AND #imm */ + .word inst2a_SYM+0 /* ROL a */ + .word inst2b_SYM+0 /* PLD */ + .word inst2c_SYM+2 /* BIT abs */ + .word inst2d_SYM+2 /* AND abs */ + .word inst2e_SYM+2 /* ROL abs */ + .word inst2f_SYM+3 /* AND long */ + .word inst30_SYM+1 /* BMI disp8 */ + .word inst31_SYM+1 /* AND (),y */ + .word inst32_SYM+1 /* AND () */ + .word inst33_SYM+1 /* AND (disp8,s),y */ + .word inst34_SYM+1 /* BIT Dloc,X */ + .word inst35_SYM+1 /* AND Dloc,x */ + .word inst36_SYM+1 /* ROL Dloc,x */ + .word inst37_SYM+1 /* AND [],y */ + .word inst38_SYM+0 /* SEC */ + .word inst39_SYM+2 /* AND abs,y */ + .word inst3a_SYM+0 /* DEC a */ + .word inst3b_SYM+0 /* TSC */ + .word inst3c_SYM+2 /* BIT Abs,X */ + .word inst3d_SYM+2 /* AND Abs,X */ + .word inst3e_SYM+2 /* ROL abs,x */ + .word inst3f_SYM+3 /* AND Long,x */ + .word inst40_SYM+0 /* RTI */ + .word inst41_SYM+1 /* EOR (Dloc,X) */ + .word inst42_SYM+1 /* WDM */ + .word inst43_SYM+1 /* EOR Disp8,S */ + .word inst44_SYM+2 /* MVP I,J */ + .word inst45_SYM+1 /* EOR Dloc */ + .word inst46_SYM+1 /* LSR Dloc */ + .word inst47_SYM+1 /* EOR [Dloc] */ + .word inst48_SYM+0 /* PHA */ + .word inst49_SYM+4 /* EOR #imm */ + .word inst4a_SYM+0 /* LSR a */ + .word inst4b_SYM+0 /* PHK */ + .word inst4c_SYM+2 /* JMP abs */ + .word inst4d_SYM+2 /* EOR abs */ + .word inst4e_SYM+2 /* LSR abs */ + .word inst4f_SYM+3 /* EOR long */ + .word inst50_SYM+1 /* BVC disp8 */ + .word inst51_SYM+1 /* EOR (),y */ + .word inst52_SYM+1 /* EOR () */ + .word inst53_SYM+1 /* EOR (disp8,s),y */ + .word inst54_SYM+2 /* MVN I,J */ + .word inst55_SYM+1 /* EOR Dloc,x */ + .word inst56_SYM+1 /* LSR Dloc,x */ + .word inst57_SYM+1 /* EOR [],y */ + .word inst58_SYM+0 /* CLI */ + .word inst59_SYM+2 /* EOR abs,y */ + .word inst5a_SYM+0 /* PHY */ + .word inst5b_SYM+0 /* TCD */ + .word inst5c_SYM+3 /* JMP Long */ + .word inst5d_SYM+2 /* EOR Abs,X */ + .word inst5e_SYM+2 /* LSR abs,x */ + .word inst5f_SYM+3 /* EOR Long,x */ + .word inst60_SYM+0 /* RTS */ + .word inst61_SYM+1 /* ADC (Dloc,X) */ + .word inst62_SYM+2 /* PER DISP16 */ + .word inst63_SYM+1 /* ADC Disp8,S */ + .word inst64_SYM+1 /* STZ Dloc */ + .word inst65_SYM+1 /* ADC Dloc */ + .word inst66_SYM+1 /* ROR Dloc */ + .word inst67_SYM+1 /* ADC [Dloc] */ + .word inst68_SYM+0 /* PLA */ + .word inst69_SYM+4 /* ADC #imm */ + .word inst6a_SYM+0 /* ROR a */ + .word inst6b_SYM+0 /* RTL */ + .word inst6c_SYM+2 /* JMP (abs) */ + .word inst6d_SYM+2 /* ADC abs */ + .word inst6e_SYM+2 /* ROR abs */ + .word inst6f_SYM+3 /* ADC long */ + .word inst70_SYM+1 /* BVS disp8 */ + .word inst71_SYM+1 /* ADC (),y */ + .word inst72_SYM+1 /* ADC () */ + .word inst73_SYM+1 /* ADC (disp8,s),y */ + .word inst74_SYM+1 /* STZ Dloc,X */ + .word inst75_SYM+1 /* ADC Dloc,x */ + .word inst76_SYM+1 /* ROR Dloc,x */ + .word inst77_SYM+1 /* ADC [],y */ + .word inst78_SYM+0 /* SEI */ + .word inst79_SYM+2 /* ADC abs,y */ + .word inst7a_SYM+0 /* PLY */ + .word inst7b_SYM+0 /* TDC */ + .word inst7c_SYM+2 /* JMP (abs,x) */ + .word inst7d_SYM+2 /* ADC Abs,X */ + .word inst7e_SYM+2 /* ROR abs,x */ + .word inst7f_SYM+3 /* ADC Long,x */ + .word inst80_SYM+1 /* BRA Disp8 */ + .word inst81_SYM+1 /* STA (Dloc,X) */ + .word inst82_SYM+2 /* BRL DISP16 */ + .word inst83_SYM+1 /* STA Disp8,S */ + .word inst84_SYM+1 /* STY Dloc */ + .word inst85_SYM+1 /* STA Dloc */ + .word inst86_SYM+1 /* STX Dloc */ + .word inst87_SYM+1 /* STA [Dloc] */ + .word inst88_SYM+0 /* DEY */ + .word inst89_SYM+4 /* BIT #imm */ + .word inst8a_SYM+0 /* TXA */ + .word inst8b_SYM+0 /* PHB */ + .word inst8c_SYM+2 /* STY abs */ + .word inst8d_SYM+2 /* STA abs */ + .word inst8e_SYM+2 /* STX abs */ + .word inst8f_SYM+3 /* STA long */ + .word inst90_SYM+1 /* BCC disp8 */ + .word inst91_SYM+1 /* STA (),y */ + .word inst92_SYM+1 /* STA () */ + .word inst93_SYM+1 /* STA (disp8,s),y */ + .word inst94_SYM+1 /* STY Dloc,X */ + .word inst95_SYM+1 /* STA Dloc,x */ + .word inst96_SYM+1 /* STX Dloc,y */ + .word inst97_SYM+1 /* STA [],y */ + .word inst98_SYM+0 /* TYA */ + .word inst99_SYM+2 /* STA abs,y */ + .word inst9a_SYM+0 /* TXS */ + .word inst9b_SYM+0 /* TXY */ + .word inst9c_SYM+2 /* STX abs */ + .word inst9d_SYM+2 /* STA Abs,X */ + .word inst9e_SYM+2 /* STZ abs,x */ + .word inst9f_SYM+3 /* STA Long,x */ + .word insta0_SYM+5 /* LDY #imm */ + .word insta1_SYM+1 /* LDA (Dloc,X) */ + .word insta2_SYM+5 /* LDX #imm */ + .word insta3_SYM+1 /* LDA Disp8,S */ + .word insta4_SYM+1 /* LDY Dloc */ + .word insta5_SYM+1 /* LDA Dloc */ + .word insta6_SYM+1 /* LDX Dloc */ + .word insta7_SYM+1 /* LDA [Dloc] */ + .word insta8_SYM+0 /* TAY */ + .word insta9_SYM+4 /* LDA #imm */ + .word instaa_SYM+0 /* TAX */ + .word instab_SYM+0 /* PLB */ + .word instac_SYM+2 /* LDY abs */ + .word instad_SYM+2 /* LDA abs */ + .word instae_SYM+2 /* LDX abs */ + .word instaf_SYM+3 /* LDA long */ + .word instb0_SYM+1 /* BCS disp8 */ + .word instb1_SYM+1 /* LDA (),y */ + .word instb2_SYM+1 /* LDA () */ + .word instb3_SYM+1 /* LDA (disp8,s),y */ + .word instb4_SYM+1 /* LDY Dloc,X */ + .word instb5_SYM+1 /* LDA Dloc,x */ + .word instb6_SYM+1 /* LDX Dloc,y */ + .word instb7_SYM+1 /* LDA [],y */ + .word instb8_SYM+0 /* CLV */ + .word instb9_SYM+2 /* LDA abs,y */ + .word instba_SYM+0 /* TSX */ + .word instbb_SYM+0 /* TYX */ + .word instbc_SYM+2 /* LDY abs,x */ + .word instbd_SYM+2 /* LDA Abs,X */ + .word instbe_SYM+2 /* LDX abs,y */ + .word instbf_SYM+3 /* LDA Long,x */ + .word instc0_SYM+5 /* CPY #Imm */ + .word instc1_SYM+1 /* CMP (Dloc,X) */ + .word instc2_SYM+1 /* REP #8bit */ + .word instc3_SYM+1 /* CMP Disp8,S */ + .word instc4_SYM+1 /* CPY Dloc */ + .word instc5_SYM+1 /* CMP Dloc */ + .word instc6_SYM+1 /* DEC Dloc */ + .word instc7_SYM+1 /* CMP [Dloc] */ + .word instc8_SYM+0 /* INY */ + .word instc9_SYM+4 /* CMP #imm */ + .word instca_SYM+0 /* DEX */ + .word instcb_SYM+0 /* WAI */ + .word instcc_SYM+2 /* CPY abs */ + .word instcd_SYM+2 /* CMP abs */ + .word instce_SYM+2 /* DEC abs */ + .word instcf_SYM+3 /* CMP long */ + .word instd0_SYM+1 /* BNE disp8 */ + .word instd1_SYM+1 /* CMP (),y */ + .word instd2_SYM+1 /* CMP () */ + .word instd3_SYM+1 /* CMP (disp8,s),y */ + .word instd4_SYM+1 /* PEI Dloc */ + .word instd5_SYM+1 /* CMP Dloc,x */ + .word instd6_SYM+1 /* DEC Dloc,x */ + .word instd7_SYM+1 /* CMP [],y */ + .word instd8_SYM+0 /* CLD */ + .word instd9_SYM+2 /* CMP abs,y */ + .word instda_SYM+0 /* PHX */ + .word instdb_SYM+0 /* STP */ + .word instdc_SYM+2 /* JML (Abs) */ + .word instdd_SYM+2 /* CMP Abs,X */ + .word instde_SYM+2 /* DEC abs,x */ + .word instdf_SYM+3 /* CMP Long,x */ + .word inste0_SYM+5 /* CPX #Imm */ + .word inste1_SYM+1 /* SBC (Dloc,X) */ + .word inste2_SYM+1 /* SEP #8bit */ + .word inste3_SYM+1 /* SBC Disp8,S */ + .word inste4_SYM+1 /* CPX Dloc */ + .word inste5_SYM+1 /* SBC Dloc */ + .word inste6_SYM+1 /* INC Dloc */ + .word inste7_SYM+1 /* SBC [Dloc] */ + .word inste8_SYM+0 /* INX */ + .word inste9_SYM+4 /* SBC #imm */ + .word instea_SYM+0 /* NOP */ + .word insteb_SYM+0 /* XBA */ + .word instec_SYM+2 /* CPX abs */ + .word insted_SYM+2 /* SBC abs */ + .word instee_SYM+2 /* INC abs */ + .word instef_SYM+3 /* SBC long */ + .word instf0_SYM+1 /* BEQ disp8 */ + .word instf1_SYM+1 /* SBC (),y */ + .word instf2_SYM+1 /* SBC () */ + .word instf3_SYM+1 /* SBC (disp8,s),y */ + .word instf4_SYM+2 /* PEA Imm */ + .word instf5_SYM+1 /* SBC Dloc,x */ + .word instf6_SYM+1 /* INC Dloc,x */ + .word instf7_SYM+1 /* SBC [],y */ + .word instf8_SYM+0 /* SED */ + .word instf9_SYM+2 /* SBC abs,y */ + .word instfa_SYM+0 /* PLX */ + .word instfb_SYM+0 /* XCE */ + .word instfc_SYM+2 /* JSR (Abs,x) */ + .word instfd_SYM+2 /* SBC Abs,X */ + .word instfe_SYM+2 /* INC abs,x */ + .word instff_SYM+3 /* SBC Long,x */ + + .block 4*16 + +#endif diff --git a/src/smartport.c b/src/smartport.c new file mode 100644 index 0000000..24ca31e --- /dev/null +++ b/src/smartport.c @@ -0,0 +1,783 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_smartport_c[] = "@(#)$KmKId: smartport.c,v 1.29 2003-11-17 15:44:44-05 kentd Exp $"; + +#include "defc.h" + +extern int Verbose; +extern int Halt_on; +extern int g_rom_version; +extern int g_io_amt; +extern int g_highest_smartport_unit; + +int g_cycs_in_io_read = 0; + +extern Engine_reg engine; + +extern Iwm iwm; + +#define LEN_SMPT_LOG 16 +STRUCT(Smpt_log) { + word32 start_addr; + int cmd; + int rts_addr; + int cmd_list; + int extras; + int unit; + int buf; + int blk; +}; + +Smpt_log g_smpt_log[LEN_SMPT_LOG]; +int g_smpt_log_pos = 0; + +void +smartport_error(void) +{ + int pos; + int i; + + pos = g_smpt_log_pos; + printf("Smartport log pos: %d\n", pos); + for(i = 0; i < LEN_SMPT_LOG; i++) { + pos--; + if(pos < 0) { + pos = LEN_SMPT_LOG - 1; + } + printf("%d:%d: t:%04x, cmd:%02x, rts:%04x, " + "cmd_l:%04x, x:%d, unit:%d, buf:%04x, blk:%04x\n", + i, pos, + g_smpt_log[pos].start_addr, + g_smpt_log[pos].cmd, + g_smpt_log[pos].rts_addr, + g_smpt_log[pos].cmd_list, + g_smpt_log[pos].extras, + g_smpt_log[pos].unit, + g_smpt_log[pos].buf, + g_smpt_log[pos].blk); + } +} +void +smartport_log(word32 start_addr, int cmd, int rts_addr, int cmd_list) +{ + int pos; + + pos = g_smpt_log_pos; + if(start_addr != 0) { + g_smpt_log[pos].start_addr = start_addr; + g_smpt_log[pos].cmd = cmd; + g_smpt_log[pos].rts_addr = rts_addr; + g_smpt_log[pos].cmd_list = cmd_list; + g_smpt_log[pos].extras = 0; + g_smpt_log[pos].unit = 0; + g_smpt_log[pos].buf = 0; + g_smpt_log[pos].blk = 0; + } else { + pos--; + if(pos < 0) { + pos = LEN_SMPT_LOG - 1; + } + g_smpt_log[pos].extras = 1; + g_smpt_log[pos].unit = cmd; + g_smpt_log[pos].buf = rts_addr; + g_smpt_log[pos].blk = cmd_list; + } + pos++; + if(pos >= LEN_SMPT_LOG) { + pos = 0; + } + g_smpt_log_pos = pos; +} + +void +do_c70d(word32 arg0) +{ + int cmd; + int cmd_list_lo, cmd_list_mid, cmd_list_hi; + int rts_lo, rts_hi; + word32 rts_addr; + word32 cmd_list; + int unit; + int param_cnt; + int status_ptr_lo, status_ptr_mid, status_ptr_hi; + int buf_ptr_lo, buf_ptr_hi; + int buf_ptr; + int block_lo, block_mid, block_hi; + int block; + word32 status_ptr; + int status_code; + int ctl_ptr_lo, ctl_ptr_hi; + int ctl_ptr; + int ctl_code; + int mask; + int stat_val; + int size; + int ret; + int ext; + int i; + + set_memory_c(0x7f8, 0xc7, 0); + + if((engine.psr & 0x100) == 0) { + disk_printf("c70d called in native mode!\n"); + if((engine.psr & 0x30) != 0x30) { + halt_printf("c70d called native, psr: %03x!\n", + engine.psr); + } + } + + engine.stack = ((engine.stack + 1) & 0xff) + 0x100; + rts_lo = get_memory_c(engine.stack, 0); + engine.stack = ((engine.stack + 1) & 0xff) + 0x100; + rts_hi = get_memory_c(engine.stack, 0); + rts_addr = (rts_lo + (256*rts_hi) + 1) & 0xffff; + disk_printf("rts_addr: %04x\n", rts_addr); + + cmd = get_memory_c(rts_addr, 0); + cmd_list_lo = get_memory_c((rts_addr + 1) & 0xffff, 0); + cmd_list_mid = get_memory_c((rts_addr + 2) & 0xffff, 0); + cmd_list_hi = 0; + mask = 0xffff; + if(cmd & 0x40) { + /* extended */ + mask = 0xffffff; + cmd_list_hi = get_memory_c((rts_addr + 3) & 0xffff, 0); + } + + cmd_list = cmd_list_lo + (256*cmd_list_mid) + (65536*cmd_list_hi); + + disk_printf("cmd: %02x, cmd_list: %06x\n", cmd, cmd_list); + param_cnt = get_memory_c(cmd_list, 0); + + ext = 0; + if(cmd & 0x40) { + ext = 2; + } + + smartport_log(0xc70d, cmd, rts_addr, cmd_list); + + switch(cmd & 0x3f) { + case 0x00: /* Status == 0x00 and 0x40 */ + if(param_cnt != 3) { + disk_printf("param_cnt %d is != 3!\n", param_cnt); + exit(8); + } + unit = get_memory_c((cmd_list+1) & mask, 0); + status_ptr_lo = get_memory_c((cmd_list+2) & mask, 0); + status_ptr_mid = get_memory_c((cmd_list+3) & mask, 0); + status_ptr_hi = 0; + if(cmd & 0x40) { + status_ptr_hi = get_memory_c((cmd_list+4) & mask, 0); + } + + status_ptr = status_ptr_lo + (256*status_ptr_mid) + + (65536*status_ptr_hi); + if(cmd & 0x40) { + status_code = get_memory_c((cmd_list+6) & mask, 0); + } else { + status_code = get_memory_c((cmd_list+4) & mask, 0); + } + + smartport_log(0, unit, status_ptr, status_code); + + disk_printf("unit: %02x, status_ptr: %06x, code: %02x\n", + unit, status_ptr, status_code); + if(unit == 0 && status_code == 0) { + /* Smartport driver status */ + /* see technotes/smpt/tn-smpt-002 */ + set_memory_c(status_ptr, g_highest_smartport_unit+1, 0); + set_memory_c(status_ptr+1, 0xff, 0); /* interrupt stat*/ + set_memory_c(status_ptr+2, 0x02, 0); /* vendor id */ + set_memory_c(status_ptr+3, 0x00, 0); /* vendor id */ + set_memory_c(status_ptr+4, 0x00, 0); /* version lo */ + set_memory_c(status_ptr+5, 0x10, 0); /* version hi */ + set_memory_c(status_ptr+6, 0x00, 0); + set_memory_c(status_ptr+7, 0x00, 0); + + engine.xreg = 8; + engine.yreg = 0; + engine.acc &= 0xff00; + engine.psr &= ~1; + engine.kpc = (rts_addr + 3 + ext) & mask; + return; + } else if(unit > 0 && status_code == 0) { + /* status for unit x */ + if(unit > MAX_C7_DISKS || iwm.smartport[unit-1].fd < 0){ + stat_val = 0x80; + size = 0; + } else { + stat_val = 0xf8; + size = iwm.smartport[unit-1].image_size; + size = (size+511) / 512; + } + set_memory_c(status_ptr, stat_val, 0); + set_memory_c(status_ptr +1, size & 0xff, 0); + set_memory_c(status_ptr +2, (size >> 8) & 0xff, 0); + set_memory_c(status_ptr +3, (size >> 16) & 0xff, 0); + engine.xreg = 4; + if(cmd & 0x40) { + set_memory_c(status_ptr + 4, + (size >> 16) & 0xff, 0); + engine.xreg = 5; + } + engine.yreg = 0; + engine.acc &= 0xff00; + engine.psr &= ~1; + engine.kpc = (rts_addr + 3 + ext) & mask; + + disk_printf("just finished unit %d, stat 0\n", unit); + return; + } else if(status_code == 3) { + if(unit > MAX_C7_DISKS || iwm.smartport[unit-1].fd < 0){ + stat_val = 0x80; + size = 0; + } else { + stat_val = 0xf8; + size = iwm.smartport[unit-1].image_size; + size = (size+511) / 512; + } + if(cmd & 0x40) { + disk_printf("extended for stat_code 3!\n"); + } + /* DIB for unit 1 */ + set_memory_c(status_ptr, stat_val, 0); + set_memory_c(status_ptr +1, size & 0xff, 0); + set_memory_c(status_ptr +2, (size >> 8) & 0xff, 0); + set_memory_c(status_ptr +3, (size >> 16) & 0xff, 0); + if(cmd & 0x40) { + set_memory_c(status_ptr + 4, + (size >> 24) & 0xff, 0); + status_ptr++; + } + set_memory_c(status_ptr +4, 4, 0); + for(i = 5; i < 21; i++) { + set_memory_c(status_ptr +i, 0x20, 0); + } + set_memory_c(status_ptr +5, 'K', 0); + set_memory_c(status_ptr +6, 'E', 0); + set_memory_c(status_ptr +7, 'G', 0); + set_memory_c(status_ptr +8, 'S', 0); + + /* hard disk supporting extended calls */ + set_memory_c(status_ptr + 21, 0x02, 0); + set_memory_c(status_ptr + 22, 0xa0, 0); + + set_memory_c(status_ptr + 23, 0x00, 0); + set_memory_c(status_ptr + 24, 0x00, 0); + + if(cmd & 0x40) { + engine.xreg = 26; + } else { + engine.xreg = 25; + } + engine.yreg = 0; + engine.acc &= 0xff00; + engine.psr &= ~1; + engine.kpc = (rts_addr + 3 + ext) & 0xffff; + + disk_printf("Just finished unit %d, stat 3\n", unit); + if(unit == 0 || unit > MAX_C7_DISKS) { + engine.acc |= 0x28; + engine.psr |= 1; + } + return; + } + printf("cmd: 00, unknown unit/status code!\n"); + break; + case 0x01: /* Read Block == 0x01 and 0x41 */ + if(param_cnt != 3) { + halt_printf("param_cnt %d is != 3!\n", param_cnt); + return; + } + unit = get_memory_c((cmd_list+1) & mask, 0); + buf_ptr_lo = get_memory_c((cmd_list+2) & mask, 0); + buf_ptr_hi = get_memory_c((cmd_list+3) & mask, 0); + + buf_ptr = buf_ptr_lo + (256*buf_ptr_hi); + if(cmd & 0x40) { + buf_ptr_lo = get_memory_c((cmd_list+4) & mask, 0); + buf_ptr_hi = get_memory_c((cmd_list+5) & mask, 0); + buf_ptr += ((buf_ptr_hi*256) + buf_ptr_lo)*65536; + cmd_list += 2; + } + block_lo = get_memory_c((cmd_list+4) & mask, 0); + block_mid = get_memory_c((cmd_list+5) & mask, 0); + block_hi = get_memory_c((cmd_list+6) & mask, 0); + block = ((block_hi*256) + block_mid)*256 + block_lo; + disk_printf("smartport read unit %d of block %04x into %04x\n", + unit, block, buf_ptr); + if(unit < 1 || unit > MAX_C7_DISKS) { + halt_printf("Unknown unit #: %d\n", unit); + } + + smartport_log(0, unit - 1, buf_ptr, block); + + ret = do_read_c7(unit - 1, buf_ptr, block); + engine.xreg = 0; + engine.yreg = 2; + engine.acc = (engine.acc & 0xff00) | (ret & 0xff); + engine.psr &= ~1; + if(ret != 0) { + engine.psr |= 1; + } + engine.kpc = (rts_addr + 3 + ext) & 0xffff; + + return; + break; + case 0x02: /* Write Block == 0x02 and 0x42 */ + if(param_cnt != 3) { + halt_printf("param_cnt %d is != 3!\n", param_cnt); + return; + } + unit = get_memory_c((cmd_list+1) & mask, 0); + buf_ptr_lo = get_memory_c((cmd_list+2) & mask, 0); + buf_ptr_hi = get_memory_c((cmd_list+3) & mask, 0); + + buf_ptr = buf_ptr_lo + (256*buf_ptr_hi); + if(cmd & 0x40) { + buf_ptr_lo = get_memory_c((cmd_list+4) & mask, 0); + buf_ptr_hi = get_memory_c((cmd_list+5) & mask, 0); + buf_ptr += ((buf_ptr_hi*256) + buf_ptr_lo)*65536; + cmd_list += 2; + } + block_lo = get_memory_c((cmd_list+4) & mask, 0); + block_mid = get_memory_c((cmd_list+5) & mask, 0); + block_hi = get_memory_c((cmd_list+6) & mask, 0); + block = ((block_hi*256) + block_mid)*256 + block_lo; + disk_printf("smartport write unit %d of block %04x from %04x\n", + unit, block, buf_ptr); + if(unit < 1 || unit > MAX_C7_DISKS) { + halt_printf("Unknown unit #: %d\n", unit); + } + + smartport_log(0, unit - 1, buf_ptr, block); + + ret = do_write_c7(unit - 1, buf_ptr, block); + engine.xreg = 0; + engine.yreg = 2; + engine.acc = (engine.acc & 0xff00) | (ret & 0xff); + engine.psr &= ~1; + if(ret != 0) { + engine.psr |= 1; + } + engine.kpc = (rts_addr + 3 + ext) & 0xffff; + + HALT_ON(HALT_ON_C70D_WRITES, "c70d Write done\n"); + return; + break; + case 0x03: /* Format == 0x03 and 0x43 */ + if(param_cnt != 1) { + halt_printf("param_cnt %d is != 1!\n", param_cnt); + return; + } + unit = get_memory_c((cmd_list+1) & mask, 0); + + if(unit < 1 || unit > MAX_C7_DISKS) { + halt_printf("Unknown unit #: %d\n", unit); + } + + smartport_log(0, unit - 1, 0, 0); + + ret = do_format_c7(unit - 1); + engine.xreg = 0; + engine.yreg = 2; + engine.acc = (engine.acc & 0xff00) | (ret & 0xff); + engine.psr &= ~1; + if(ret != 0) { + engine.psr |= 1; + } + engine.kpc = (rts_addr + 3 + ext) & 0xffff; + + HALT_ON(HALT_ON_C70D_WRITES, "c70d Format done\n"); + return; + break; + case 0x04: /* Control == 0x04 and 0x44 */ + if(cmd == 0x44) { + halt_printf("smartport code 0x44 not supported\n"); + } + if(param_cnt != 3) { + halt_printf("param_cnt %d is != 3!\n", param_cnt); + return; + } + unit = get_memory_c((cmd_list+1) & mask, 0); + ctl_ptr_lo = get_memory_c((cmd_list+2) & mask, 0); + ctl_ptr_hi = get_memory_c((cmd_list+3) & mask, 0); + + ctl_ptr = (ctl_ptr_hi << 8) + ctl_ptr_lo; + if(cmd & 0x40) { + ctl_ptr_lo = get_memory_c((cmd_list+4) & mask, 0); + ctl_ptr_hi = get_memory_c((cmd_list+5) & mask, 0); + ctl_ptr += ((ctl_ptr_hi << 8) + ctl_ptr_lo) << 16; + cmd_list += 2; + } + + ctl_code = get_memory_c((cmd_list +4) & mask, 0); + + switch(ctl_code) { + case 0x00: + printf("Performing a reset on unit %d\n", unit); + break; + default: + halt_printf("control code: %02x unknown!\n", ctl_code); + } + + engine.xreg = 0; + engine.yreg = 2; + engine.acc &= 0xff00; + engine.psr &= ~1; + engine.kpc = (rts_addr + 3 + ext) & 0xffff; + return; + break; + default: /* Unknown command! */ + /* set acc = 1, and set carry, and set kpc */ + engine.xreg = (rts_addr) & 0xff; + engine.yreg = (rts_addr >> 8) & 0xff; + engine.acc = (engine.acc & 0xff00) + 0x01; + engine.psr |= 0x01; /* set carry */ + engine.kpc = (rts_addr + 3 + ext) & 0xffff; + if(cmd != 0x4a && cmd != 0x48) { + /* Finder does 0x4a call before formatting disk */ + /* Many things do 0x48 call to see online drives */ + halt_printf("Just did smtport cmd:%02x rts_addr:%04x, " + "cmdlst:%06x\n", cmd, rts_addr, cmd_list); + } + return; + } + + halt_printf("Unknown smtport cmd:%02x, cmd_list:%06x, rts_addr:%06x\n", + cmd, cmd_list, rts_addr); +} + +void +do_c70a(word32 arg0) +{ + int cmd, unit; + int buf_lo, buf_hi; + int blk_lo, blk_hi; + int blk, buf; + int prodos_unit; + int size; + int ret; + + set_memory_c(0x7f8, 0xc7, 0); + + cmd = get_memory_c((engine.direct + 0x42) & 0xffff, 0); + prodos_unit = get_memory_c((engine.direct + 0x43) & 0xffff, 0); + buf_lo = get_memory_c((engine.direct + 0x44) & 0xffff, 0); + buf_hi = get_memory_c((engine.direct + 0x45) & 0xffff, 0); + blk_lo = get_memory_c((engine.direct + 0x46) & 0xffff, 0); + blk_hi = get_memory_c((engine.direct + 0x47) & 0xffff, 0); + + blk = (blk_hi << 8) + blk_lo; + buf = (buf_hi << 8) + buf_lo; + disk_printf("cmd: %02x, pro_unit: %02x, buf: %04x, blk: %04x\n", + cmd, prodos_unit, buf, blk); + + if((prodos_unit & 0x7f) == 0x70) { + unit = 0 + (prodos_unit >> 7); + } else if((prodos_unit & 0x7f) == 0x40) { + unit = 2 + (prodos_unit >> 7); + } else { + halt_printf("Unknown prodos_unit: %d\n", prodos_unit); + return; + } + + smartport_log(0xc70a, cmd, blk, buf); + + engine.psr &= ~1; /* clear carry */ + if(g_rom_version >= 3) { + engine.kpc = 0xc764; + } else { + engine.kpc = 0xc765; + } + + ret = 0x27; /* I/O error */ + if(cmd == 0x00) { + size = iwm.smartport[unit].image_size; + size = (size+511) / 512; + + smartport_log(0, unit, size, 0); + + ret = 0; + engine.xreg = size & 0xff; + engine.yreg = size >> 8; + } else if(cmd == 0x01) { + smartport_log(0, unit, buf, blk); + ret = do_read_c7(unit, buf, blk); + } else if(cmd == 0x02) { + smartport_log(0, unit, buf, blk); + ret = do_write_c7(unit, buf, blk); + } else if(cmd == 0x03) { /* format */ + smartport_log(0, unit, buf, blk); + ret = do_format_c7(unit); + } + + engine.acc = (engine.acc & 0xff00) | (ret & 0xff); + if(ret != 0) { + engine.psr |= 1; + } + return; +} + +int +do_read_c7(int unit_num, word32 buf, int blk) +{ + byte local_buf[0x200]; + register word32 start_time; + register word32 end_time; + word32 val; + int len; + int fd; + int image_start; + int image_size; + int ret; + int i; + + if(unit_num < 0 || unit_num > MAX_C7_DISKS) { + halt_printf("do_read_c7: unit_num: %d\n", unit_num); + smartport_error(); + return 0x28; + } + + fd = iwm.smartport[unit_num].fd; + image_start = iwm.smartport[unit_num].image_start; + image_size = iwm.smartport[unit_num].image_size; + if(fd < 0) { + printf("c7_fd == %d!\n", fd); +#if 0 + if(blk != 2 && blk != 0) { + /* don't print error if only reading directory */ + smartport_error(); + halt_printf("Read unit:%02x blk:%04x\n", unit_num, blk); + } +#endif + return 0x2f; + } + + ret = lseek(fd, image_start + blk*0x200, SEEK_SET); + if(ret != image_start + blk*0x200) { + halt_printf("lseek returned %08x, errno: %d\n", ret, errno); + smartport_error(); + return 0x27; + } + + if(ret >= image_start + image_size) { + halt_printf("Tried to read from pos %08x on disk, (blk:%04x)\n", + ret, blk); + smartport_error(); + return 0x27; + } + + len = read(fd, &local_buf[0], 0x200); + if(len != 0x200) { + printf("read returned %08x, errno:%d, blk:%04x, unit: %02x\n", + len, errno, blk, unit_num); + halt_printf("name: %s\n", iwm.smartport[unit_num].name_ptr); + smartport_error(); + return 0x27; + } + + g_io_amt += 0x200; + + if(buf >= 0xfc0000) { + disk_printf("reading into ROM, just returning\n"); + return 0; + } + + GET_ITIMER(start_time); + + for(i = 0; i < 0x200; i += 2) { + val = (local_buf[i+1] << 8) + local_buf[i]; + set_memory16_c(buf + i, val, 0); + } + + GET_ITIMER(end_time); + + g_cycs_in_io_read += (end_time - start_time); + + return 0; + +} + +int +do_write_c7(int unit_num, word32 buf, int blk) +{ + word32 local_buf[0x200/4]; + Disk *dsk; + word32 *ptr; + word32 val1, val2; + word32 val; + int len; + int ret; + int fd; + int image_start; + int image_size; + int i; + + if(unit_num < 0 || unit_num > MAX_C7_DISKS) { + halt_printf("do_write_c7: unit_num: %d\n", unit_num); + smartport_error(); + return 0x28; + } + + dsk = &(iwm.smartport[unit_num]); + fd = dsk->fd; + image_start = dsk->image_start; + image_size = dsk->image_size; + if(fd < 0) { + halt_printf("c7_fd == %d!\n", fd); + smartport_error(); + return 0x28; + } + + ptr = &(local_buf[0]); + for(i = 0; i < 0x200; i += 4) { + val1 = get_memory16_c(buf + i, 0); + val2 = get_memory16_c(buf + i + 2, 0); + /* reorder the little-endian bytes to be big-endian */ +#ifdef KEGS_LITTLE_ENDIAN + val = (val2 << 16) + val1; +#else + val = (val1 << 24) + ((val1 << 8) & 0xff0000) + + ((val2 << 8) & 0xff00) + (val2 >> 8); +#endif + *ptr++ = val; + } + + ret = lseek(fd, image_start + blk*0x200, SEEK_SET); + if(ret != image_start + blk*0x200) { + halt_printf("lseek returned %08x, errno: %d\n", ret, errno); + smartport_error(); + return 0x27; + } + + if(ret >= image_start + image_size) { + halt_printf("Tried to write to %08x\n", ret); + smartport_error(); + return 0x27; + } + + if(dsk->write_prot) { + printf("Write, but %s is write protected!\n", dsk->name_ptr); + return 0x2b; + } + + if(dsk->write_through_to_unix == 0) { + halt_printf("Write to %s, but not wr_thru!\n", dsk->name_ptr); + return 0x00; + } + + len = write(fd, (byte *)&local_buf[0], 0x200); + if(len != 0x200) { + halt_printf("write ret %08x bytes, errno: %d\n", len, errno); + smartport_error(); + return 0x27; + } + + g_io_amt += 0x200; + + return 0; + +} + +int +do_format_c7(int unit_num) +{ + byte local_buf[0x1000]; + Disk *dsk; + int len; + int ret; + int sum; + int total; + int max; + int image_start; + int image_size; + int fd; + int i; + + if(unit_num < 0 || unit_num > MAX_C7_DISKS) { + halt_printf("do_format_c7: unit_num: %d\n", unit_num); + smartport_error(); + return 0x28; + } + + dsk = &(iwm.smartport[unit_num]); + fd = dsk->fd; + image_start = dsk->image_start; + image_size = dsk->image_size; + if(fd < 0) { + halt_printf("c7_fd == %d!\n", fd); + smartport_error(); + return 0x28; + } + + for(i = 0; i < 0x1000; i++) { + local_buf[i] = 0; + } + + ret = lseek(fd, image_start, SEEK_SET); + if(ret != image_start) { + halt_printf("lseek returned %08x, errno: %d\n", ret, errno); + smartport_error(); + return 0x27; + } + + if(dsk->write_prot) { + printf("Format, but %s is write protected!\n", dsk->name_ptr); + return 0x2b; + } + + if(dsk->write_through_to_unix == 0) { + printf("Format of %s ignored\n", dsk->name_ptr); + return 0x00; + } + + sum = 0; + total = image_size; + + while(sum < total) { + max = MIN(0x1000, total-sum); + len = write(fd, &local_buf[0], max); + if(len != max) { + halt_printf("write ret %08x, errno:%d\n", len, errno); + smartport_error(); + return 0x27; + } + sum += len; + } + + return 0; +} + + +void +do_c700(word32 ret) +{ + disk_printf("do_c700 called, ret: %08x\n", ret); + + ret = do_read_c7(0, 0x800, 0); + + set_memory_c(0x7f8, 7, 0); + set_memory_c(0x42, 0x01, 0); + set_memory_c(0x43, 0x70, 0); + set_memory_c(0x44, 0x0, 0); + set_memory_c(0x45, 0x8, 0); + set_memory_c(0x46, 0x0, 0); + set_memory_c(0x47, 0x0, 0); + engine.xreg = 0x70; + engine.kpc = 0x801; + + if(ret != 0) { + printf("Failure reading boot disk in s7d1!\n"); + engine.kpc = 0xe000; + } +} + diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 0000000..2ba8d06 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,2031 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_sound_c[] = "@(#)$KmKId: sound.c,v 1.103 2003-10-17 15:07:47-04 kentd Exp $"; + +#include "defc.h" + +#define INCLUDE_RCSID_C +#include "sound.h" +#undef INCLUDE_RCSID_C + +#if 0 +# define DO_DOC_LOG +#endif + +extern int Verbose; +extern int g_use_shmem; +extern word32 g_vbl_count; +extern int g_preferred_rate; + + +extern double g_last_vbl_dcycs; + +void U_STACK_TRACE(); + +byte doc_ram[0x10000 + 16]; + +word32 doc_sound_ctl = 0; +word32 doc_saved_val = 0; +word32 doc_ptr = 0; +int g_doc_num_osc_en = 1; +double g_dcycs_per_doc_update = 1.0; +double g_dupd_per_dcyc = 1.0; +double g_drecip_osc_en_plus_2 = 1.0 / (double)(1 + 2); + +int g_doc_saved_ctl = 0; +int g_queued_samps = 0; +int g_queued_nonsamps = 0; +int g_num_osc_interrupting = 0; + +#if defined(HPUX) || defined(__linux__) || defined(_WIN32) || defined(MAC) +int g_audio_enable = -1; +#else +# if defined(OSS) +/* default to off for now */ +int g_audio_enable = 0; +# else +/* Default to sound off */ +int g_audio_enable = 0; +# endif +#endif + +Doc_reg g_doc_regs[32]; + +word32 doc_reg_e0 = 0xff; + +/* local function prototypes */ +void doc_write_ctl_reg(int osc, int val, double dsamps); + + +int g_audio_rate = 0; +double g_daudio_rate = 0.0; +double g_drecip_audio_rate = 0.0; +double g_dsamps_per_dcyc = 0.0; +double g_dcycs_per_samp = 0.0; +float g_fsamps_per_dcyc = 0.0; + +int g_doc_vol = 2; + +#define MAX_C030_TIMES 18000 + +double g_last_sound_play_dsamp = 0.0; + +float c030_fsamps[MAX_C030_TIMES + 1]; +int g_num_c030_fsamps = 0; + +#define DOC_SCAN_RATE (DCYCS_28_MHZ/32.0) + +int g_pipe_fd[2] = { -1, -1 }; +int g_pipe2_fd[2] = { -1, -1 }; +word32 *g_sound_shm_addr = 0; +int g_sound_shm_pos = 0; + +#define LEN_DOC_LOG 128 + +STRUCT(Doc_log) { + char *msg; + int osc; + double dsamps; + double dtmp2; + int etc; + Doc_reg doc_reg; +}; + +Doc_log g_doc_log[LEN_DOC_LOG]; +int g_doc_log_pos = 0; + + +#ifdef DO_DOC_LOG +# define DOC_LOG(a,b,c,d) doc_log_rout(a,b,c,d) +#else +# define DOC_LOG(a,b,c,d) +#endif + +#define UPDATE_G_DCYCS_PER_DOC_UPDATE(osc_en) \ + g_dcycs_per_doc_update = (double)((osc_en + 2) * DCYCS_1_MHZ) / \ + DOC_SCAN_RATE; \ + g_dupd_per_dcyc = 1.0 / g_dcycs_per_doc_update; \ + g_drecip_osc_en_plus_2 = 1.0 / (double)(osc_en + 2); + +#define SND_PTR_SHIFT 14 +#define SND_PTR_SHIFT_DBL ((double)(1 << SND_PTR_SHIFT)) + +void +doc_log_rout(char *msg, int osc, double dsamps, int etc) +{ + int pos; + + pos = g_doc_log_pos; + g_doc_log[pos].msg = msg; + g_doc_log[pos].osc = osc; + g_doc_log[pos].dsamps = dsamps; + g_doc_log[pos].dtmp2 = g_last_sound_play_dsamp; + g_doc_log[pos].etc = etc; + if(osc >= 0 && osc < 32) { + g_doc_log[pos].doc_reg = g_doc_regs[osc]; + } + pos++; + if(pos >= LEN_DOC_LOG) { + pos = 0; + } + + doc_printf("log: %s, osc:%d dsamp:%f, etc:%d\n", msg, osc, dsamps, etc); + + g_doc_log_pos = pos; +} + +extern double g_cur_dcycs; + +void +show_doc_log(void) +{ + FILE *docfile; + Doc_reg *rptr; + double dsamp_start; + int osc, ctl, freq; + int pos; + int i; + + docfile = fopen("doc_log_out", "wt"); + if(docfile == 0) { + printf("fopen failed, errno: %d\n", errno); + return; + } + pos = g_doc_log_pos; + fprintf(docfile, "DOC log pos: %d\n", pos); + dsamp_start = g_doc_log[pos].dsamps; + for(i = 0; i < LEN_DOC_LOG; i++) { + rptr = &(g_doc_log[pos].doc_reg); + osc = g_doc_log[pos].osc; + ctl = rptr->ctl; + freq = rptr->freq; + if(osc < 0) { + ctl = 0; + freq = 0; + } + fprintf(docfile, "%03x:%03x: %-11s ds:%11.1f dt2:%10.1f " + "etc:%08x o:%02x c:%02x fq:%04x\n", + i, pos, g_doc_log[pos].msg, + g_doc_log[pos].dsamps - dsamp_start, + g_doc_log[pos].dtmp2, + g_doc_log[pos].etc, osc & 0xff, ctl, freq); + if(osc >= 0) { + fprintf(docfile, " ire:%d,%d,%d ptr4:%08x " + "inc4:%08x comp_ds:%.1f left:%04x, vol:%02x " + "wptr:%02x, wsz:%02x, 4st:%08x, 4end:%08x\n", + rptr->has_irq_pending, rptr->running, + rptr->event, 4*rptr->cur_acc, 4*rptr->cur_inc, + rptr->complete_dsamp - dsamp_start, + rptr->samps_left, rptr->vol, rptr->waveptr, + rptr->wavesize, 4*rptr->cur_start, + 4*rptr->cur_end); + } + pos++; + if(pos >= LEN_DOC_LOG) { + pos = 0; + } + } + + fprintf(docfile, "cur_dcycs: %f\n", g_cur_dcycs); + fprintf(docfile, "dsamps_now: %f\n", + (g_cur_dcycs * g_dsamps_per_dcyc) - dsamp_start); + fprintf(docfile, "g_doc_num_osc_en: %d\n", g_doc_num_osc_en); + fclose(docfile); +} + +void +sound_init() +{ + Doc_reg *rptr; + int i; + + for(i = 0; i < 32; i++) { + rptr = &(g_doc_regs[i]); + rptr->dsamp_ev = 0.0; + rptr->dsamp_ev2 = 0.0; + rptr->complete_dsamp = 0.0; + rptr->samps_left = 0; + rptr->cur_acc = 0; + rptr->cur_inc = 0; + rptr->cur_start = 0; + rptr->cur_end = 0; + rptr->cur_mask = 0; + rptr->size_bytes = 0; + rptr->event = 0; + rptr->running = 0; + rptr->has_irq_pending = 0; + rptr->freq = 0; + rptr->vol = 0; + rptr->waveptr = 0; + rptr->ctl = 1; + rptr->wavesize = 0; + rptr->last_samp_val = 0; + } + + sound_init_general(); +} + + +void +sound_init_general() +{ +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) + int pid; + int shmid; + int tmp; + int i; +#endif + word32 *shmaddr; + int size; + int ret; + +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) + if(!g_use_shmem) { + if(g_audio_enable < 0) { + printf("Defaulting audio off for slow X display\n"); + g_audio_enable = 0; + } + } +#endif + ret = 0; + + if(g_audio_enable == 0) { + set_audio_rate(g_preferred_rate); + return; + } + + size = SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE; + +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) + shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); + if(shmid < 0) { + printf("sound_init: shmget ret: %d, errno: %d\n", shmid, + errno); + exit(2); + } + + shmaddr = shmat(shmid, 0, 0); + tmp = (int)PTR2WORD(shmaddr); + if(tmp == -1) { + printf("sound_init: shmat ret: %p, errno: %d\n", shmaddr, + errno); + exit(3); + } + + ret = shmctl(shmid, IPC_RMID, 0); + if(ret < 0) { + printf("sound_init: shmctl ret: %d, errno: %d\n", ret, errno); + exit(4); + } +#else +/* windows and mac */ + shmaddr = malloc(size); + memset(shmaddr, 0, size); +#endif + + g_sound_shm_addr = shmaddr; + + fflush(stdout); + +#if !defined(MAC) && !defined(_WIN32) && !defined(__CYGWIN__) + /* prepare pipe so parent can signal child each other */ + /* pipe[0] = read side, pipe[1] = write end */ + ret = pipe(&g_pipe_fd[0]); + if(ret < 0) { + printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno); + exit(5); + } + ret = pipe(&g_pipe2_fd[0]); + if(ret < 0) { + printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno); + exit(5); + } + + + printf("pipes: pipe_fd = %d, %d pipe2_fd: %d,%d\n", + g_pipe_fd[0], g_pipe_fd[1], g_pipe2_fd[0], g_pipe2_fd[1]); + fflush(stdout); + + pid = fork(); + switch(pid) { + case 0: + /* child */ + /* close stdin and write-side of pipe */ + close(0); + /* Close other fds to make sure X window fd is closed */ + for(i = 3; i < 100; i++) { + if((i != g_pipe_fd[0]) && (i != g_pipe2_fd[1])) { + close(i); + } + } + close(g_pipe_fd[1]); /*make sure write pipe closed*/ + close(g_pipe2_fd[0]); /*make sure read pipe closed*/ + child_sound_loop(g_pipe_fd[0], g_pipe2_fd[1], g_sound_shm_addr); + printf("Child sound loop returned\n"); + exit(0); + case -1: + /* error */ + printf("sound_init: fork ret: -1, errno: %d\n", errno); + exit(6); + default: + /* parent */ + /* close read-side of pipe1, and the write side of pipe2 */ + close(g_pipe_fd[0]); + close(g_pipe2_fd[1]); + doc_printf("Child is pid: %d\n", pid); + } + + parent_sound_get_sample_rate(g_pipe2_fd[0]); +#else +# ifdef MAC + macsnd_init(shmaddr); +# else +/* windows */ + win32snd_init(shmaddr); +# endif +#endif /* _WIN32 */ + +} + +void +parent_sound_get_sample_rate(int read_fd) +{ + word32 tmp; + int ret; + + ret = read(read_fd, &tmp, 4); + if(ret != 4) { + printf("parent dying, could not get sample rate from child\n"); + printf("ret: %d, fd: %d errno:%d\n", ret, read_fd, errno); + exit(1); + } + close(read_fd); + + set_audio_rate(tmp); +} + +void +set_audio_rate(int rate) +{ + g_audio_rate = rate; + g_daudio_rate = (rate)*1.0; + g_drecip_audio_rate = 1.0/(rate); + g_dsamps_per_dcyc = ((rate*1.0) / DCYCS_1_MHZ); + g_dcycs_per_samp = (DCYCS_1_MHZ / (rate*1.0)); + g_fsamps_per_dcyc = (float)((rate*1.0) / DCYCS_1_MHZ); +} + +void +sound_reset(double dcycs) +{ + double dsamps; + int i; + + dsamps = dcycs * g_dsamps_per_dcyc; + for(i = 0; i < 32; i++) { + doc_write_ctl_reg(i, g_doc_regs[i].ctl | 1, dsamps); + doc_reg_e0 = 0xff; + if(g_doc_regs[i].has_irq_pending) { + halt_printf("reset: has_irq[%02x] = %d\n", i, + g_doc_regs[i].has_irq_pending); + } + } + if(g_num_osc_interrupting) { + halt_printf("reset: num_osc_int:%d\n", g_num_osc_interrupting); + } + + g_doc_num_osc_en = 1; + UPDATE_G_DCYCS_PER_DOC_UPDATE(1); +} + +void +sound_shutdown() +{ +#ifdef _WIN32 + win32snd_shutdown(); +#else + if((g_audio_enable != 0) && g_pipe_fd[1] != 0) { + close(g_pipe_fd[1]); + } +#endif +} + + + +void +sound_update(double dcycs) +{ + double dsamps; + /* Called every VBL time to update sound status */ + + /* "play" sounds for this vbl */ + + dsamps = dcycs * g_dsamps_per_dcyc; + DOC_LOG("do_snd_pl", -1, dsamps, 0); + sound_play(dsamps); +} + +#define MAX_SND_BUF 65536 + +int g_samp_buf[2*MAX_SND_BUF]; +word32 zero_buf[SOUND_SHM_SAMP_SIZE]; + +double g_doc_dsamps_extra = 0.0; + +float g_fvoices = 0.0; + +word32 g_cycs_in_sound1 = 0; +word32 g_cycs_in_sound2 = 0; +word32 g_cycs_in_sound3 = 0; +word32 g_cycs_in_sound4 = 0; +word32 g_cycs_in_start_sound = 0; +word32 g_cycs_in_est_sound = 0; + +int g_num_snd_plays = 0; +int g_num_doc_events = 0; +int g_num_start_sounds = 0; +int g_num_scan_osc = 0; +int g_num_recalc_snd_parms = 0; + +word32 g_last_c030_vbl_count = 0; +int g_c030_state = 0; + +#define VAL_C030_RANGE (32768) +#define VAL_C030_BASE (-16384) + +int g_sound_file_num = 0; +int g_sound_file_fd = -1; +int g_send_sound_to_file = 0; +int g_send_file_bytes = 0; + +void +open_sound_file() +{ + char name[256]; + int fd; + + sprintf(name, "snd.out.%d", g_sound_file_num); + + fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0x1ff); + if(fd < 0) { + printf("open_sound_file open ret: %d, errno: %d\n", fd, errno); + exit(1); + } + + g_sound_file_fd = fd; + g_sound_file_num++; + g_send_file_bytes = 0; +} + +void +close_sound_file() +{ + if(g_sound_file_fd >= 0) { + close(g_sound_file_fd); + } + + g_sound_file_fd = -1; +} + +void +check_for_range(word32 *addr, int num_samps, int offset) +{ + short *shortptr; + int i; + int left; + int right; + int max; + + max = -32768; + + if(num_samps > SOUND_SHM_SAMP_SIZE) { + halt_printf("num_samps: %d > %d!\n", num_samps, + SOUND_SHM_SAMP_SIZE); + } + + for(i = 0; i < num_samps; i++) { + shortptr = (short *)&(addr[i]); + left = shortptr[0]; + right = shortptr[1]; + if((left > 0x3000) || (right > 0x3000)) { + halt_printf("Sample %d of %d at snd_buf: %p is: " + "%d/%d\n", i + offset, num_samps, + &addr[i], left, right); + return; + } + + max = MAX(max, left); + max = MAX(max, right); + } + + printf("check4 max: %d over %d\n", max, num_samps); +} + +void +send_sound_to_file(word32 *addr, int shm_pos, int num_samps) +{ + int size; + int ret; + + if(g_sound_file_fd < 0) { + open_sound_file(); + } + + size = 0; + if((num_samps + shm_pos) > SOUND_SHM_SAMP_SIZE) { + size = SOUND_SHM_SAMP_SIZE - shm_pos; + g_send_file_bytes += (size * 4); + + ret = write(g_sound_file_fd, &(addr[shm_pos]), 4*size); + if(ret != 4*size) { + halt_printf("wrote %d not %d\n", ret, 4*size); + } + + if(g_doc_vol < 3) { + check_for_range(&(addr[shm_pos]), size, 0); + } else { + printf("Not checking %d bytes since vol: %d\n", + 4*size, g_doc_vol); + } + shm_pos = 0; + num_samps -= size; + } + + g_send_file_bytes += (num_samps * 4); + + ret = write(g_sound_file_fd, &(addr[shm_pos]), 4*num_samps); + if(ret != 4*num_samps) { + halt_printf("wrote %d not %d\n", ret, 4*num_samps); + } + + if(g_doc_vol < 3) { + check_for_range(&(addr[shm_pos]), num_samps, size); + } else { + printf("Not checking2 %d bytes since vol: %d\n", + 4*num_samps, g_doc_vol); + } + +} + +void +send_sound(int real_samps, int size) +{ + word32 tmp; + int ret; + + if(g_audio_enable == 0) { + printf("Entered send_sound but audio off!\n"); + exit(2); + } + + if(real_samps) { + tmp = size + 0xa2000000; + } else { + tmp = size + 0xa1000000; + } + DOC_LOG("send_sound", -1, g_last_sound_play_dsamp, + (real_samps << 30) + size); + +#if defined(MAC) || defined(_WIN32) + ret = 0; + child_sound_playit(tmp); +#else + /* Although this looks like a big/little-endian issue, since the */ + /* child is also reading an int, it just works with no byte swap */ + ret = write(g_pipe_fd[1], &tmp, 4); + if(ret != 4) { + halt_printf("send_sound, wr ret: %d, errno: %d\n", ret, errno); + } +#endif +} + +void +show_c030_state() +{ + show_c030_samps(&(g_samp_buf[0]), 100); +} + +void +show_c030_samps(int *outptr, int num) +{ + int i; + + printf("c030_fsamps[]: %d\n", g_num_c030_fsamps); + + for(i = 0; i < g_num_c030_fsamps+2; i++) { + printf("%3d: %5.3f\n", i, c030_fsamps[i]); + } + + printf("Samples[] = %d\n", num); + + for(i = 0; i < num+2; i++) { + printf("%4d: %d %d\n", i, outptr[0], outptr[1]); + outptr += 2; + } +} + +int g_sound_play_depth = 0; + +void +sound_play(double dsamps) +{ + register word32 start_time1, start_time2, start_time3, start_time4; + register word32 end_time1, end_time2, end_time3; + Doc_reg *rptr; + int *outptr; + int *outptr_start; + word32 *sndptr; + double complete_dsamp; + double cur_dsamp; + double last_dsamp; + double dsamp_now; + double dnum_samps; + int val, val2; + int new_val; + float ftmp; + int imul; + int off; + int num; + float fsampnum; + float next_fsampnum; + int c030_lo_val, c030_hi_val; + float fc030_range; + float fc030_base; + int sampnum; + int next_sampnum; + float fpercent; + int c030_state; + int val0, val1; + word32 cur_acc; + word32 cur_pos; + word32 cur_mask; + word32 cur_inc; + word32 cur_end; + int ctl; + int num_osc_en; + int samps_left; + int samps_to_do; + int samps_played; + int samp_offset; + int snd_buf_init; + int pos; + int num_running; + int num_samps; + int osc; + int done; + int i, j; + + + GET_ITIMER(start_time1); + + g_num_snd_plays++; + if(g_sound_play_depth) { + halt_printf("Nested sound_play!\n"); + } + + g_sound_play_depth++; + + /* calc sample num */ + + last_dsamp = g_last_sound_play_dsamp; + num_samps = (int)(dsamps - g_last_sound_play_dsamp); + dnum_samps = (double)num_samps; + + dsamp_now = last_dsamp + dnum_samps; + + if(num_samps < 1) { + /* just say no */ + g_sound_play_depth--; + return; + } + + DOC_LOG("sound_play", -1, dsamp_now, num_samps); + + if(num_samps > MAX_SND_BUF) { + printf("num_samps: %d, too big!\n", num_samps); + g_sound_play_depth--; + return; + } + + + GET_ITIMER(start_time4); + + outptr_start = &(g_samp_buf[0]); + outptr = outptr_start; + + snd_buf_init = 0; + + samps_played = 0; + + num = g_num_c030_fsamps; + + if(num || ((g_vbl_count - g_last_c030_vbl_count) < 240)) { + + if(num) { + g_last_c030_vbl_count = g_vbl_count; + } + + pos = 0; + outptr = outptr_start; + c030_state = g_c030_state; + + c030_hi_val = ((VAL_C030_BASE + VAL_C030_RANGE)*g_doc_vol) >> 4; + c030_lo_val = (VAL_C030_BASE * g_doc_vol) >> 4; + + fc030_range = (float)(((VAL_C030_RANGE) * g_doc_vol) >> 4); + fc030_base = (float)(((VAL_C030_BASE) * g_doc_vol) >> 4); + + val = c030_lo_val; + if(c030_state) { + val = c030_hi_val; + } + + snd_buf_init++; + + c030_fsamps[num] = (float)(num_samps); + c030_fsamps[num+1] = (float)(num_samps+1); + + ftmp = (float)num_samps; + /* ensure that all samps are in range */ + for(i = num - 1; i >= 0; i--) { + if(c030_fsamps[i] > ftmp) { + c030_fsamps[i] = ftmp; + } + } + + num++; + fsampnum = c030_fsamps[0]; + sampnum = (int)fsampnum; + fpercent = (float)0.0; + i = 0; + + while(i < num) { + next_fsampnum = c030_fsamps[i+1]; + next_sampnum = (int)next_fsampnum; + if(sampnum < 0 || sampnum > num_samps) { + halt_printf("play c030: [%d]:%f is %d, > %d\n", + i, fsampnum, sampnum, num_samps); + break; + } + + /* write in samples to all samps < me */ + new_val = c030_lo_val; + if(c030_state) { + new_val = c030_hi_val; + } + for(j = pos; j < sampnum; j++) { + outptr[0] = new_val; + outptr[1] = new_val; + outptr += 2; + pos++; + } + + /* now, calculate me */ + fpercent = (float)0.0; + if(c030_state) { + fpercent = (fsampnum - (float)sampnum); + } + + c030_state = !c030_state; + + while(next_sampnum == sampnum) { + if(c030_state) { + fpercent += (next_fsampnum - fsampnum); + } + i++; + fsampnum = next_fsampnum; + + next_fsampnum = c030_fsamps[i+1]; + next_sampnum = (int)next_fsampnum; + c030_state = !c030_state; + } + + if(c030_state) { + /* add in fractional time */ + ftmp = (int)(fsampnum + (float)1.0); + fpercent += (ftmp - fsampnum); + } + + if((fpercent < (float)0.0) || (fpercent > (float)1.0)) { + halt_printf("fpercent: %d = %f\n", i, fpercent); + show_c030_samps(outptr_start, num_samps); + break; + } + + val = (int)((fpercent * fc030_range) + fc030_base); + outptr[0] = val; + outptr[1] = val; + outptr += 2; + pos++; + i++; + + sampnum = next_sampnum; + fsampnum = next_fsampnum; + } + + samps_played += num_samps; + + /* since we pretended to get one extra sample, we will */ + /* have toggled the speaker one time too many. Fix it */ + g_c030_state = !c030_state; + + if(g_send_sound_to_file) { + show_c030_samps(outptr_start, num_samps); + } + } + + g_num_c030_fsamps = 0; + + GET_ITIMER(start_time2); + + num_running = 0; + + num_osc_en = g_doc_num_osc_en; + + done = 0; + while(!done) { + done = 1; + for(j = 0; j < num_osc_en; j++) { + osc = j; + rptr = &(g_doc_regs[osc]); + complete_dsamp = rptr->complete_dsamp; + samps_left = rptr->samps_left; + cur_acc = rptr->cur_acc; + cur_mask = rptr->cur_mask; + cur_inc = rptr->cur_inc; + cur_end = rptr->cur_end; + if(!rptr->running || cur_inc == 0 || + (complete_dsamp >= dsamp_now)) { + continue; + } + + done = 0; + ctl = rptr->ctl; + + samp_offset = 0; + if(complete_dsamp > last_dsamp) { + samp_offset = (int)(complete_dsamp- last_dsamp); + if(samp_offset > num_samps) { + rptr->complete_dsamp = dsamp_now; + continue; + } + } + outptr = outptr_start + 2 * samp_offset; + if(ctl & 0x10) { + /* other channel */ + outptr += 1; + } + + imul = (rptr->vol * g_doc_vol); + off = imul * 128; + + samps_to_do = MIN(samps_left, num_samps - samp_offset); + if(imul == 0 || samps_to_do == 0) { + /* produce no sound */ + samps_left = samps_left - samps_to_do; + cur_acc += cur_inc * samps_to_do; + rptr->samps_left = samps_left; + rptr->cur_acc = cur_acc; + cur_dsamp = last_dsamp + + (double)(samps_to_do + samp_offset); + DOC_LOG("nosnd", osc, cur_dsamp, samps_to_do); + rptr->complete_dsamp = dsamp_now; + cur_pos = rptr->cur_start+(cur_acc & cur_mask); + if(samps_left <= 0) { + doc_sound_end(osc, 1, cur_dsamp, + dsamp_now); + val = 0; + j--; + } else { + val = doc_ram[cur_pos >> SND_PTR_SHIFT]; + } + rptr->last_samp_val = val; + continue; + } + + if(snd_buf_init == 0) { + memset(outptr_start, 0, + 2*sizeof(outptr_start[0])*num_samps); + snd_buf_init++; + } + + val = 0; + rptr->complete_dsamp = dsamp_now; + cur_pos = rptr->cur_start + (cur_acc & cur_mask); + for(i = 0; i < samps_to_do; i++) { + pos = cur_pos >> SND_PTR_SHIFT; + cur_pos += cur_inc; + cur_acc += cur_inc; + val = doc_ram[pos]; + + val2 = (val * imul - off) >> 4; + if((val == 0) || (cur_pos >= cur_end)) { + cur_dsamp = last_dsamp + + (double)(samp_offset + i + 1); + rptr->cur_acc = cur_acc; + rptr->samps_left = 0; + DOC_LOG("end or 0", osc, cur_dsamp, + (pos << 16) + ((i &0xff) << 8) + + val); + doc_sound_end(osc, val, cur_dsamp, + dsamp_now); + val = 0; + break; + } + + val2 = outptr[0] + val2; + + samps_left--; + *outptr = val2; + outptr += 2; + } + + rptr->last_samp_val = val; + + if(val != 0) { + rptr->cur_acc = cur_acc; + rptr->samps_left = samps_left; + rptr->complete_dsamp = dsamp_now; + } + + samps_played += samps_to_do; + DOC_LOG("splayed", osc, dsamp_now, + (samps_to_do << 16) + (pos & 0xffff)); + } + } + + GET_ITIMER(end_time2); + + g_cycs_in_sound2 += (end_time2 - start_time2); + + g_last_sound_play_dsamp = dsamp_now; + + GET_ITIMER(start_time3); + + outptr = outptr_start; + + pos = g_sound_shm_pos; + sndptr = g_sound_shm_addr; + +#if 0 + printf("samps_left: %d, num_samps: %d\n", samps_left, num_samps); +#endif + + if(g_audio_enable != 0) { + + if(snd_buf_init) { + /* convert sound buf */ + + for(i = 0; i < num_samps; i++) { + val0 = outptr[0]; + val1 = outptr[1]; + val = val0; + if(val0 > 32767) { + val = 32767; + } + if(val0 < -32768) { + val = -32768; + } + + val0 = val; + val = val1; + if(val1 > 32767) { + val = 32767; + } + if(val1 < -32768) { + val = -32768; + } + + + outptr += 2; + +#if defined(__linux__) || defined(OSS) + /* Linux seems to expect little-endian */ + /* samples always, even on PowerPC */ +# ifdef KEGS_LITTLE_ENDIAN + sndptr[pos] = (val << 16) + (val0 & 0xffff); +# else + sndptr[pos] = ((val & 0xff) << 24) + + ((val & 0xff00) << 8) + + ((val0 & 0xff) << 8) + + ((val0 >> 8) & 0xff); +# endif +#else +# ifdef KEGS_LITTLE_ENDIAN + sndptr[pos] = (val << 16) + (val0 & 0xffff); +# else + sndptr[pos] = (val0 << 16) + (val & 0xffff); +# endif +#endif + pos++; + if(pos >= SOUND_SHM_SAMP_SIZE) { + pos = 0; + } + } + + if(g_queued_nonsamps) { + /* force out old 0 samps */ + send_sound(0, g_queued_nonsamps); + g_queued_nonsamps = 0; + } + + if(g_send_sound_to_file) { + send_sound_to_file(g_sound_shm_addr, + g_sound_shm_pos, num_samps); + } + + g_queued_samps += num_samps; + } else { + /* move pos */ + pos += num_samps; + while(pos >= SOUND_SHM_SAMP_SIZE) { + pos -= SOUND_SHM_SAMP_SIZE; + } + + if(g_send_sound_to_file) { + send_sound_to_file(zero_buf, g_sound_shm_pos, + num_samps); + } + + if(g_queued_samps) { + /* force out old non-0 samps */ + send_sound(1, g_queued_samps); + g_queued_samps = 0; + } + + g_queued_nonsamps += num_samps; + } + + } + + g_sound_shm_pos = pos; + + + GET_ITIMER(end_time3); + + g_fvoices += ((float)(samps_played) * (float)(g_drecip_audio_rate)); + + if(g_audio_enable != 0) { + if(g_queued_samps >= (g_audio_rate/32)) { + send_sound(1, g_queued_samps); + g_queued_samps = 0; + } + + if(g_queued_nonsamps >= (g_audio_rate/32)) { + send_sound(0, g_queued_nonsamps); + g_queued_nonsamps = 0; + } + } + + GET_ITIMER(end_time1); + + g_cycs_in_sound1 += (end_time1 - start_time1); + g_cycs_in_sound3 += (end_time3 - start_time3); + g_cycs_in_sound4 += (start_time2 - start_time4); + + g_last_sound_play_dsamp = dsamp_now; + + g_sound_play_depth--; +} + + +void +doc_handle_event(int osc, double dcycs) +{ + double dsamps; + + /* handle osc stopping and maybe interrupting */ + + g_num_doc_events++; + + dsamps = dcycs * g_dsamps_per_dcyc; + + DOC_LOG("doc_ev", osc, dcycs, 0); + + g_doc_regs[osc].event = 0; + + sound_play(dsamps); + +} + +void +doc_sound_end(int osc, int can_repeat, double eff_dsamps, double dsamps) +{ + Doc_reg *rptr, *orptr; + int mode, omode; + int other_osc; + int one_shot_stop; + int ctl; + + /* handle osc stopping and maybe interrupting */ + + if(osc < 0 || osc > 31) { + printf("doc_handle_event: osc: %d!\n", osc); + return; + } + + rptr = &(g_doc_regs[osc]); + ctl = rptr->ctl; + + if(rptr->event) { + remove_event_doc(osc); + } + rptr->event = 0; + rptr->cur_acc = 0; /* reset internal accumulator*/ + + /* check to make sure osc is running */ + if(ctl & 0x01) { + /* Oscillator already stopped. */ + halt_printf("Osc %d interrupt, but it was already stop!\n",osc); +#ifdef HPUX + U_STACK_TRACE(); +#endif + return; + } + + if(ctl & 0x08) { + if(rptr->has_irq_pending == 0) { + add_sound_irq(osc); + } + } + + if(!rptr->running) { + halt_printf("Doc event for osc %d, but ! running\n", osc); + } + + rptr->running = 0; + + mode = (ctl >> 1) & 3; + other_osc = osc ^ 1; + orptr = &(g_doc_regs[other_osc]); + omode = (orptr->ctl >> 1) & 3; + + /* If either this osc or it's partner is in swap mode, treat the */ + /* pair as being in swap mode. This Ensoniq feature pointed out */ + /* by Ian Schmidt */ + if(mode == 0 && can_repeat) { + /* free-running mode with no 0 byte! */ + /* start doing it again */ + + start_sound(osc, eff_dsamps, dsamps); + + return; + } else if((mode == 3) || (omode == 3)) { + /* swap mode (even if we're one_shot and partner is swap)! */ + /* unless we're one-shot and we hit a 0-byte--then */ + /* Olivier Goguel says just stop */ + rptr->ctl |= 1; + one_shot_stop = (mode == 1) && (!can_repeat); + if(!one_shot_stop && !orptr->running && + (orptr->ctl & 0x1)) { + orptr->ctl = orptr->ctl & (~1); + start_sound(other_osc, eff_dsamps, dsamps); + } + return; + } else { + /* stop the oscillator */ + rptr->ctl |= 1; + } + + return; +} + +void +add_sound_irq(int osc) +{ + int num_osc_interrupting; + + if(g_doc_regs[osc].has_irq_pending) { + halt_printf("Adding sound_irq for %02x, but irq_p: %d\n", osc, + g_doc_regs[osc].has_irq_pending); + } + + num_osc_interrupting = g_num_osc_interrupting + 1; + g_doc_regs[osc].has_irq_pending = num_osc_interrupting; + g_num_osc_interrupting = num_osc_interrupting; + + add_irq(); + if(num_osc_interrupting == 1) { + doc_reg_e0 = 0x00 + (osc << 1); + } + + DOC_LOG("add_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); +} + +void +remove_sound_irq(int osc, int must) +{ + Doc_reg *rptr; + int num_osc_interrupt; + int has_irq_pending; + int first; + int i; + + doc_printf("remove irq for osc: %d, has_irq: %d\n", + osc, g_doc_regs[osc].has_irq_pending); + + num_osc_interrupt = g_doc_regs[osc].has_irq_pending; + first = 0; + if(num_osc_interrupt) { + g_num_osc_interrupting--; + g_doc_regs[osc].has_irq_pending = 0; + DOC_LOG("rem_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); + remove_irq(); + + first = 0x40 | (doc_reg_e0 >> 1); + /* if none found, then def = no ints */ + for(i = 0; i < g_doc_num_osc_en; i++) { + rptr = &(g_doc_regs[i]); + has_irq_pending = rptr->has_irq_pending; + if(has_irq_pending > num_osc_interrupt) { + has_irq_pending--; + rptr->has_irq_pending = has_irq_pending; + } + if(has_irq_pending == 1) { + first = i; + } + } + if(num_osc_interrupt == 1) { + doc_reg_e0 = (first << 1); + } else { +#if 0 + halt_printf("remove_sound_irq[%02x]=%d, first:%d\n", + osc, num_osc_interrupt, first); +#endif + } + } else { +#if 0 + /* make sure no int pending */ + if(doc_reg_e0 != 0xff) { + halt_printf("remove_sound_irq[%02x]=0, but e0: %02x\n", + osc, doc_reg_e0); + } +#endif + if(must) { + halt_printf("REMOVE_sound_irq[%02x]=0, but e0: %02x\n", + osc, doc_reg_e0); + } + } + + if(doc_reg_e0 & 0x80) { + for(i = 0; i < 0x20; i++) { + has_irq_pending = g_doc_regs[i].has_irq_pending; + if(has_irq_pending) { + halt_printf("remove_sound_irq[%02x], but " + "[%02x]=%d!\n", osc,i,has_irq_pending); + printf("num_osc_int: %d, first: %02x\n", + num_osc_interrupt, first); + } + } + } +} + +void +start_sound(int osc, double eff_dsamps, double dsamps) +{ + register word32 start_time1; + register word32 end_time1; + Doc_reg *rptr; + int ctl; + int mode; + word32 sz; + word32 size; + word32 wave_size; + + if(osc < 0 || osc > 31) { + halt_printf("start_sound: osc: %02x!\n", osc); + } + + g_num_start_sounds++; + + rptr = &(g_doc_regs[osc]); + + if(osc >= g_doc_num_osc_en) { + rptr->ctl |= 1; + return; + } + + GET_ITIMER(start_time1); + + ctl = rptr->ctl; + + mode = (ctl >> 1) & 3; + + wave_size = rptr->wavesize; + + sz = ((wave_size >> 3) & 7) + 8; + size = 1 << sz; + + if(size < 0x100) { + halt_printf("size: %08x is too small, sz: %08x!\n", size, sz); + } + + if(rptr->running) { + halt_printf("start_sound osc: %d, already running!\n", osc); + } + + rptr->running = 1; + + rptr->complete_dsamp = eff_dsamps; + + doc_printf("Starting osc %02x, dsamp: %f\n", osc, dsamps); + doc_printf("size: %04x\n", size); + + if((mode == 2) && ((osc & 1) == 0)) { + printf("Sync mode osc %d starting!\n", osc); + /* set_halt(1); */ + + /* see if we should start our odd partner */ + if((rptr[1].ctl & 7) == 5) { + /* odd partner stopped in sync mode--start him */ + rptr[1].ctl &= (~1); + start_sound(osc + 1, eff_dsamps, dsamps); + } else { + printf("Osc %d starting sync, but osc %d ctl: %02x\n", + osc, osc+1, rptr[1].ctl); + } + } + + wave_end_estimate(osc, eff_dsamps, dsamps); + + DOC_LOG("st playing", osc, eff_dsamps, size); +#if 0 + if(rptr->cur_acc != 0) { + halt_printf("Start osc %02x, acc: %08x\n", osc, rptr->cur_acc); + } +#endif + + GET_ITIMER(end_time1); + + g_cycs_in_start_sound += (end_time1 - start_time1); +} + +void +wave_end_estimate(int osc, double eff_dsamps, double dsamps) +{ + register word32 start_time1; + register word32 end_time1; + Doc_reg *rptr; + byte *ptr1; + double event_dsamp; + double event_dcycs; + double dcycs_per_samp; + double dsamps_per_byte; + double num_dsamps; + double dcur_inc; + word32 tmp1; + word32 cur_inc; + word32 save_val; + int save_size; + int pos; + int size; + int estimate; + + GET_ITIMER(start_time1); + + dcycs_per_samp = g_dcycs_per_samp; + + rptr = &(g_doc_regs[osc]); + + cur_inc = rptr->cur_inc; + dcur_inc = (double)cur_inc; + dsamps_per_byte = 0.0; + if(cur_inc) { + dsamps_per_byte = SND_PTR_SHIFT_DBL / (double)dcur_inc; + } + + /* see if there's a zero byte */ + tmp1 = rptr->cur_start + (rptr->cur_acc & rptr->cur_mask); + pos = tmp1 >> SND_PTR_SHIFT; + size = ((rptr->cur_end) >> SND_PTR_SHIFT) - pos; + + ptr1 = &doc_ram[pos]; + + estimate = 0; + if(rptr->ctl & 0x08 || g_doc_regs[osc ^ 1].ctl & 0x08) { + estimate = 1; + } + +#if 0 + estimate = 1; +#endif + if(estimate) { + save_size = size; + save_val = ptr1[size]; + ptr1[size] = 0; + size = strlen((char *)ptr1); + ptr1[save_size] = save_val; + } + + /* calc samples to play */ + num_dsamps = (dsamps_per_byte * (double)size) + 1.0; + + rptr->samps_left = (int)num_dsamps; + + if(rptr->event) { + remove_event_doc(osc); + } + rptr->event = 0; + + event_dsamp = eff_dsamps + num_dsamps; + if(estimate) { + rptr->event = 1; + rptr->dsamp_ev = event_dsamp; + rptr->dsamp_ev2 = dsamps; + event_dcycs = (event_dsamp * dcycs_per_samp) + 1.0; + add_event_doc(event_dcycs, osc); + } + + GET_ITIMER(end_time1); + + g_cycs_in_est_sound += (end_time1 - start_time1); +} + + +void +remove_sound_event(int osc) +{ + if(g_doc_regs[osc].event) { + g_doc_regs[osc].event = 0; + remove_event_doc(osc); + } +} + + +void +doc_write_ctl_reg(int osc, int val, double dsamps) +{ + Doc_reg *rptr; + double eff_dsamps; + word32 old_halt; + word32 new_halt; + int old_val; + int mode; + + if(osc < 0 || osc >= 0x20) { + halt_printf("doc_write_ctl_reg: osc: %02x, val: %02x\n", + osc, val); + return; + } + + eff_dsamps = dsamps; + rptr = &(g_doc_regs[osc]); + old_val = rptr->ctl; + g_doc_saved_ctl = old_val; + + if(old_val == val) { + return; + } + + DOC_LOG("ctl_reg", osc, dsamps, (old_val << 16) + val); + + mode = (val >> 1) & 3; + + old_halt = (old_val & 1); + new_halt = (val & 1); + + /* bits are: 28: old int bit */ + /* 29: old halt bit */ + /* 30: new int bit */ + /* 31: new halt bit */ + +#if 0 + if(osc == 0x10) { + printf("osc %d new_ctl: %02x, old: %02x\n", osc, val, old_val); + } +#endif + + /* no matter what, remove any pending IRQs on this osc */ + remove_sound_irq(osc, 0); + +#if 0 + if(old_halt) { + printf("doc_write_ctl to osc %d, val: %02x, old: %02x\n", + osc, val, old_val); + } +#endif + + if(new_halt != 0) { + /* make sure sound is stopped */ + remove_sound_event(osc); + if(old_halt == 0) { + /* it was playing, finish it up */ +#if 0 + halt_printf("Aborted osc %d at eff_dsamps: %f, ctl: " + "%02x, oldctl: %02x\n", osc, eff_dsamps, + val, old_val); +#endif + sound_play(eff_dsamps); + } + if(((old_val >> 1) & 3) > 0) { + /* don't clear acc if free-running */ + g_doc_regs[osc].cur_acc = 0; + } + + g_doc_regs[osc].ctl = val; + g_doc_regs[osc].running = 0; + } else { + /* new halt == 0 = make sure sound is running */ + if(old_halt != 0) { + /* start sound */ + DOC_LOG("ctl_sound_play", osc, eff_dsamps, val); + sound_play(eff_dsamps); + g_doc_regs[osc].ctl = val; + + start_sound(osc, eff_dsamps, dsamps); + } else { + /* was running, and something changed */ + doc_printf("osc %d old ctl:%02x new:%02x!\n", + osc, old_val, val); +#if 0 + sound_play(eff_dsamps); +/* HACK: fix this??? */ +#endif + g_doc_regs[osc].ctl = val; + if((old_val ^ val) & val & 0x8) { + /* now has ints on */ + wave_end_estimate(osc, dsamps, dsamps); + } + } + } +} + +void +doc_recalc_sound_parms(int osc, double eff_dcycs, double dsamps) +{ + Doc_reg *rptr; + double dfreq; + double dtmp1; + double dacc, dacc_recip; + word32 res; + word32 sz; + word32 size; + word32 wave_size; + word32 cur_start; + word32 shifted_size; + + g_num_recalc_snd_parms++; + + rptr = &(g_doc_regs[osc]); + + wave_size = rptr->wavesize; + + dfreq = (double)rptr->freq; + + sz = ((wave_size >> 3) & 7) + 8; + size = 1 << sz; + rptr->size_bytes = size; + res = wave_size & 7; + + shifted_size = size << SND_PTR_SHIFT; + cur_start = (rptr->waveptr << (8 + SND_PTR_SHIFT)) & (-shifted_size); + + dtmp1 = dfreq * (DOC_SCAN_RATE * g_drecip_audio_rate); + dacc = (double)(1 << (20 - (17 - sz + res))); + dacc_recip = (SND_PTR_SHIFT_DBL) / ((double)(1 << 20)); + dtmp1 = dtmp1 * g_drecip_osc_en_plus_2 * dacc * dacc_recip; + + rptr->cur_inc = (int)(dtmp1); + rptr->cur_start = cur_start; + rptr->cur_end = cur_start + shifted_size; + rptr->cur_mask = (shifted_size - 1); + + DOC_LOG("recalc", osc, dsamps, (rptr->waveptr << 16) + wave_size); +} + +int +doc_read_c030(double dcycs) +{ + int num; + + num = g_num_c030_fsamps; + if(num >= MAX_C030_TIMES) { + halt_printf("Too many clicks per vbl: %d\n", num); + return 0; + } + + c030_fsamps[num] = (float)(dcycs * g_dsamps_per_dcyc - + g_last_sound_play_dsamp); + g_num_c030_fsamps = num + 1; + + doc_printf("read c030, num this vbl: %04x\n", num); + + return 0; +} + +int +doc_read_c03c(double dcycs) +{ + return doc_sound_ctl; +} + +int +doc_read_c03d(double dcycs) +{ + double dsamps; + Doc_reg *rptr; + int osc; + int type; + int ret; + + ret = doc_saved_val; + dsamps = dcycs * g_dsamps_per_dcyc; + + if(doc_sound_ctl & 0x40) { + /* Read RAM */ + doc_saved_val = doc_ram[doc_ptr]; + } else { + /* Read DOC */ + doc_saved_val = 0; + + osc = doc_ptr & 0x1f; + type = (doc_ptr >> 5) & 0x7; + rptr = &(g_doc_regs[osc]); + + switch(type) { + case 0x0: /* freq lo */ + doc_saved_val = rptr->freq & 0xff; + break; + case 0x1: /* freq hi */ + doc_saved_val = rptr->freq >> 8; + break; + case 0x2: /* vol */ + doc_saved_val = rptr->vol; + break; + case 0x3: /* data register */ + /* HACK: make this call sound_play sometimes */ + doc_saved_val = rptr->last_samp_val; + break; + case 0x4: /* wave ptr register */ + doc_saved_val = rptr->waveptr; + break; + case 0x5: /* control register */ + doc_saved_val = rptr->ctl; + break; + case 0x6: /* control register */ + doc_saved_val = rptr->wavesize; + break; + case 0x7: /* 0xe0-0xff */ + switch(osc) { + case 0x00: /* 0xe0 */ + doc_saved_val = doc_reg_e0; + doc_printf("Reading doc 0xe0, ret: %02x\n", + doc_saved_val); + + /* Clear IRQ on read of e0, if any irq pend */ + if((doc_reg_e0 & 0x80) == 0) { + remove_sound_irq(doc_reg_e0 >> 1, 1); + } + break; + case 0x01: /* 0xe1 */ + doc_saved_val = (g_doc_num_osc_en - 1) << 1; + break; + case 0x02: /* 0xe2 */ + doc_saved_val = 0x80; +#if 0 + halt_printf("Reading doc 0xe2, ret: %02x\n", + doc_saved_val); +#endif + break; + default: + doc_saved_val = 0; + halt_printf("Reading bad doc_reg[%04x]: %02x\n", + doc_ptr, doc_saved_val); + } + break; + default: + doc_saved_val = 0; + halt_printf("Reading bad doc_reg[%04x]: %02x\n", + doc_ptr, doc_saved_val); + } + } + + doc_printf("read c03d, doc_ptr: %04x, ret: %02x, saved: %02x\n", + doc_ptr, ret, doc_saved_val); + + DOC_LOG("read c03d", -1, dsamps, (doc_ptr << 16) + + (doc_saved_val << 8) + ret); + + if(doc_sound_ctl & 0x20) { + doc_ptr = (doc_ptr + 1) & 0xffff; + } + + + return ret; +} + +void +doc_write_c03c(int val, double dcycs) +{ + int vol; + + vol = val & 0xf; + if(g_doc_vol != vol) { + /* don't bother playing sound..wait till next update */ + /* sound_play(dcycs); */ + + g_doc_vol = vol; + doc_printf("Setting doc vol to 0x%x at %f\n", + vol, dcycs); + } + DOC_LOG("c03c write", -1, dcycs * g_dsamps_per_dcyc, val); + + doc_sound_ctl = val; +} + +void +doc_write_c03d(int val, double dcycs) +{ + double dsamps; + double eff_dsamps; + Doc_reg *rptr; + int osc; + int type; + int ctl; + int tmp; + int i; + + val = val & 0xff; + + dsamps = dcycs * g_dsamps_per_dcyc; + eff_dsamps = dsamps; + doc_printf("write c03d, doc_ptr: %04x, val: %02x\n", + doc_ptr, val); + + DOC_LOG("write c03d", -1, dsamps, (doc_ptr << 16) + val); + + if(doc_sound_ctl & 0x40) { + /* RAM */ + doc_ram[doc_ptr] = val; + } else { + /* DOC */ + osc = doc_ptr & 0x1f; + type = (doc_ptr >> 5) & 0x7; + + rptr = &(g_doc_regs[osc]); + ctl = rptr->ctl; +#if 0 + if((ctl & 1) == 0) { + if(type < 2 || type == 4 || type == 6) { + halt_printf("Osc %d is running, old ctl: %02x, " + "but write reg %02x=%02x\n", + osc, ctl, doc_ptr & 0xff, val); + } + } +#endif + + switch(type) { + case 0x0: /* freq lo */ + if((rptr->freq & 0xff) == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("flo_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->freq = (rptr->freq & 0xff00) + val; + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x1: /* freq hi */ + if((rptr->freq >> 8) == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("fhi_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->freq = (rptr->freq & 0xff) + (val << 8); + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x2: /* vol */ + if(rptr->vol == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("vol_sound_play", osc, dsamps, val); + sound_play(dsamps); +#if 0 + halt_printf("vol_sound_play at %.1f osc:%d " + "val:%d\n", dsamps, osc, val); +#endif + } + rptr->vol = val; + break; + case 0x3: /* data register */ +#if 0 + printf("Writing %02x into doc_data_reg[%02x]!\n", + val, osc); +#endif + break; + case 0x4: /* wave ptr register */ + if(rptr->waveptr == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("wptr_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->waveptr = val; + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x5: /* control register */ +#if 0 + printf("doc_write ctl osc %d, val: %02x\n", osc, val); +#endif + if(rptr->ctl == (word32)val) { + break; + } + doc_write_ctl_reg(osc, val, dsamps); + break; + case 0x6: /* wavesize register */ + if(rptr->wavesize == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("wsz_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->wavesize = val; + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x7: /* 0xe0-0xff */ + switch(osc) { + case 0x00: /* 0xe0 */ + doc_printf("writing doc 0xe0 with %02x, " + "was:%02x\n", val, doc_reg_e0); +#if 0 + if(val != doc_reg_e0) { + halt_printf("writing doc 0xe0 with " + "%02x, was:%02x\n", val, + doc_reg_e0); + } +#endif + break; + case 0x01: /* 0xe1 */ + doc_printf("Writing doc 0xe1 with %02x\n", val); + tmp = val & 0x3e; + tmp = (tmp >> 1) + 1; + if(tmp < 1) { + tmp = 1; + } + if(tmp > 32) { + halt_printf("doc 0xe1: %02x!\n", val); + tmp = 32; + } + g_doc_num_osc_en = tmp; + UPDATE_G_DCYCS_PER_DOC_UPDATE(tmp); + + /* Stop any oscs that were running but now */ + /* are disabled */ + for(i = g_doc_num_osc_en; i < 0x20; i++) { + doc_write_ctl_reg(i, + g_doc_regs[i].ctl | 1, dsamps); + } + + break; + default: + /* this should be illegal, but Turkey Shoot */ + /* and apparently TaskForce, OOTW, etc */ + /* writes to e2-ff, for no apparent reason */ + doc_printf("Writing doc 0x%x with %02x\n", + doc_ptr, val); + break; + } + break; + default: + halt_printf("Writing %02x into bad doc_reg[%04x]\n", + val, doc_ptr); + } + } + + if(doc_sound_ctl & 0x20) { + doc_ptr = (doc_ptr + 1) & 0xffff; + } + + doc_saved_val = val; +} + +void +doc_write_c03e(int val) +{ + doc_ptr = (doc_ptr & 0xff00) + val; +} + +void +doc_write_c03f(int val) +{ + doc_ptr = (doc_ptr & 0xff) + (val << 8); +} + +void +doc_show_ensoniq_state(int osc) +{ + Doc_reg *rptr; + int i; + + printf("Ensoniq state\n"); + printf("c03c doc_sound_ctl: %02x, doc_saved_val: %02x\n", + doc_sound_ctl, doc_saved_val); + printf("doc_ptr: %04x, num_osc_en: %02x, e0: %02x\n", doc_ptr, + g_doc_num_osc_en, doc_reg_e0); + + for(i = 0; i < 32; i += 8) { + printf("irqp: %02x: %04x %04x %04x %04x %04x %04x %04x %04x\n", + i, + g_doc_regs[i].has_irq_pending, + g_doc_regs[i + 1].has_irq_pending, + g_doc_regs[i + 2].has_irq_pending, + g_doc_regs[i + 3].has_irq_pending, + g_doc_regs[i + 4].has_irq_pending, + g_doc_regs[i + 5].has_irq_pending, + g_doc_regs[i + 6].has_irq_pending, + g_doc_regs[i + 7].has_irq_pending); + } + + for(i = 0; i < 32; i += 8) { + printf("freq: %02x: %04x %04x %04x %04x %04x %04x %04x %04x\n", + i, + g_doc_regs[i].freq, g_doc_regs[i + 1].freq, + g_doc_regs[i + 2].freq, g_doc_regs[i + 3].freq, + g_doc_regs[i + 4].freq, g_doc_regs[i + 5].freq, + g_doc_regs[i + 6].freq, g_doc_regs[i + 7].freq); + } + + for(i = 0; i < 32; i += 8) { + printf("vol: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", + i, + g_doc_regs[i].vol, g_doc_regs[i + 1].vol, + g_doc_regs[i + 2].vol, g_doc_regs[i + 3].vol, + g_doc_regs[i + 4].vol, g_doc_regs[i + 5].vol, + g_doc_regs[i + 6].vol, g_doc_regs[i + 6].vol); + } + + for(i = 0; i < 32; i += 8) { + printf("wptr: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", + i, + g_doc_regs[i].waveptr, g_doc_regs[i + 1].waveptr, + g_doc_regs[i + 2].waveptr, g_doc_regs[i + 3].waveptr, + g_doc_regs[i + 4].waveptr, g_doc_regs[i + 5].waveptr, + g_doc_regs[i + 6].waveptr, g_doc_regs[i + 7].waveptr); + } + + for(i = 0; i < 32; i += 8) { + printf("ctl: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", + i, + g_doc_regs[i].ctl, g_doc_regs[i + 1].ctl, + g_doc_regs[i + 2].ctl, g_doc_regs[i + 3].ctl, + g_doc_regs[i + 4].ctl, g_doc_regs[i + 5].ctl, + g_doc_regs[i + 6].ctl, g_doc_regs[i + 7].ctl); + } + + for(i = 0; i < 32; i += 8) { + printf("wsize: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", + i, + g_doc_regs[i].wavesize, g_doc_regs[i + 1].wavesize, + g_doc_regs[i + 2].wavesize, g_doc_regs[i + 3].wavesize, + g_doc_regs[i + 4].wavesize, g_doc_regs[i + 5].wavesize, + g_doc_regs[i + 6].wavesize, g_doc_regs[i + 7].wavesize); + } + + show_doc_log(); + + for(i = 0; i < 32; i++) { + rptr = &(g_doc_regs[i]); + printf("%2d: ctl:%02x wp:%02x ws:%02x freq:%04x vol:%02x " + "ev:%d run:%d irq:%d sz:%04x\n", i, + rptr->ctl, rptr->waveptr, rptr->wavesize, rptr->freq, + rptr->vol, rptr->event, rptr->running, + rptr->has_irq_pending, rptr->size_bytes); + printf(" acc:%08x inc:%08x st:%08x end:%08x m:%08x\n", + rptr->cur_acc, rptr->cur_inc, rptr->cur_start, + rptr->cur_end, rptr->cur_mask); + printf(" compl_ds:%f samps_left:%d ev:%f ev2:%f\n", + rptr->complete_dsamp, rptr->samps_left, + rptr->dsamp_ev, rptr->dsamp_ev2); + } + +#if 0 + for(osc = 0; osc < 32; osc++) { + fmax = 0.0; + printf("osc %d has %d samps\n", osc, g_fsamp_num[osc]); + for(i = 0; i < g_fsamp_num[osc]; i++) { + printf("%4d: %f\n", i, g_fsamps[osc][i]); + fmax = MAX(fmax, g_fsamps[osc][i]); + } + printf("osc %d, fmax: %f\n", osc, fmax); + } +#endif +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 0000000..552d5cf --- /dev/null +++ b/src/sound.h @@ -0,0 +1,60 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +#ifdef INCLUDE_RCSID_C +const char rcsid_sound_h[] = "@(#)$KmKId: sound.h,v 1.17 2003-11-21 15:15:57-05 kentd Exp $"; +#endif + +#if !defined(_WIN32) && !defined(__CYGWIN__) +# include +# include +#endif + +#define SOUND_SHM_SAMP_SIZE (32*1024) + +#define SAMPLE_SIZE 2 +#define NUM_CHANNELS 2 +#define SAMPLE_CHAN_SIZE (SAMPLE_SIZE * NUM_CHANNELS) + +STRUCT(Doc_reg) { + double dsamp_ev; + double dsamp_ev2; + double complete_dsamp; + int samps_left; + word32 cur_acc; + word32 cur_inc; + word32 cur_start; + word32 cur_end; + word32 cur_mask; + int size_bytes; + int event; + int running; + int has_irq_pending; + word32 freq; + word32 vol; + word32 waveptr; + word32 ctl; + word32 wavesize; + word32 last_samp_val; +}; + +/* prototypes for win32snd_driver.c functions */ +void win32snd_init(word32 *); +void win32snd_shutdown(); +void win32snd_shutdown(); +void child_sound_init_win32(); +int win32_send_audio(byte *ptr, int size); + + +/* Prototypes for macsnd_driver.c functions */ +int mac_send_audio(byte *ptr, int in_size); +void child_sound_init_mac(); +void macsnd_init(word32 *shmaddr); + diff --git a/src/sound_driver.c b/src/sound_driver.c new file mode 100644 index 0000000..30f9b61 --- /dev/null +++ b/src/sound_driver.c @@ -0,0 +1,469 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_sound_driver_c[] = "@(#)$KmKId: sound_driver.c,v 1.16 2004-03-22 19:08:08-05 kentd Exp $"; + +#include "defc.h" +#include "sound.h" + +#ifdef HPUX +# include +#endif + +#ifdef SOLARIS +# include +#endif + +#if defined(__linux__) || defined(OSS) +# include +#endif + +#ifndef _WIN32 +# include +# include +#endif +#include + + +extern int Verbose; +extern int g_use_alib; + +extern int g_audio_rate; + +int g_preferred_rate = 48000; +int g_audio_socket = -1; +int g_bytes_written = 0; + +#define ZERO_BUF_SIZE 2048 + +word32 g_snd_zero_buf[ZERO_BUF_SIZE]; + +#define ZERO_PAUSE_SAFETY_SAMPS (g_audio_rate >> 5) +#define ZERO_PAUSE_NUM_SAMPS (4*g_audio_rate) + +int g_zeroes_buffered = 0; +int g_zeroes_seen = 0; +int g_sound_paused = 0; +int g_childsnd_vbl = 0; +int g_childsnd_pos = 0; +word32 *g_childsnd_shm_addr = 0; + +void child_sound_init_linux(); +void child_sound_init_hpdev(); +void child_sound_init_solaris(); +void child_sound_init_win32(); +void child_sound_init_mac(); + +void +reliable_buf_write(word32 *shm_addr, int pos, int size) +{ + byte *ptr; + int ret; + + if(size < 1 || pos < 0 || pos > SOUND_SHM_SAMP_SIZE || + size > SOUND_SHM_SAMP_SIZE || + (pos + size) > SOUND_SHM_SAMP_SIZE) { + printf("reliable_buf_write: pos: %04x, size: %04x\n", + pos, size); + exit(1); + } + + ptr = (byte *)&(shm_addr[pos]); + size = size * 4; + + while(size > 0) { +#ifdef _WIN32 + ret = win32_send_audio(ptr, size); +#else +# ifdef MAC + ret = mac_send_audio(ptr, size); +# else + ret = write(g_audio_socket, ptr, size); +# endif +#endif + + if(ret < 0) { + printf("audio write, errno: %d\n", errno); + exit(1); + } + size = size - ret; + ptr += ret; + g_bytes_written += ret; + } + +} + +void +reliable_zero_write(int amt) +{ + int len; + + while(amt > 0) { + len = MIN(amt, ZERO_BUF_SIZE); + reliable_buf_write(g_snd_zero_buf, 0, len); + amt -= len; + } +} + + +void +child_sound_loop(int read_fd, int write_fd, word32 *shm_addr) +{ +#ifdef HPUX + long status_return; +#endif + word32 tmp; + int ret; + + doc_printf("Child pipe fd: %d\n", read_fd); + + g_audio_rate = g_preferred_rate; + + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + g_sound_paused = 0; + + g_childsnd_pos = 0; + g_childsnd_vbl = 0; + g_childsnd_shm_addr = shm_addr; + +#ifdef HPUX + child_sound_init_hpdev(); +#endif +#ifdef SOLARIS + child_sound_init_solaris(); +#endif +#if defined(__linux__) || defined(OSS) + child_sound_init_linux(); +#endif +#ifdef _WIN32 + child_sound_init_win32(); + return; +#endif +#ifdef MAC + child_sound_init_mac(); + return; +#endif + + tmp = g_audio_rate; + ret = write(write_fd, &tmp, 4); + if(ret != 4) { + printf("Unable to send back audio rate to parent\n"); + printf("ret: %d fd: %d, errno: %d\n", ret, write_fd, errno); + exit(1); + } + printf("Wrote to fd %d the audio rate\n", write_fd); + + close(write_fd); + + while(1) { + errno = 0; + ret = read(read_fd, &tmp, 4); + if(ret <= 0) { + printf("child dying from ret: %d, errno: %d\n", + ret, errno); + break; + } + + child_sound_playit(tmp); + } + +#ifdef HPUX + ioctl(g_audio_socket, AUDIO_DRAIN, 0); +#endif + close(g_audio_socket); + + exit(0); +} + +void +child_sound_playit(word32 tmp) +{ + int size; + + size = tmp & 0xffffff; + + //printf("child_sound_playit: %08x\n", tmp); + + if((tmp >> 24) == 0xa2) { + /* play sound here */ + + +#if 0 + g_childsnd_pos += g_zeroes_buffered; + while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { + g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; + } +#endif + + if(g_zeroes_buffered) { + reliable_zero_write(g_zeroes_buffered); + } + + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + + if((size + g_childsnd_pos) > SOUND_SHM_SAMP_SIZE) { + reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, + SOUND_SHM_SAMP_SIZE - g_childsnd_pos); + size = (g_childsnd_pos + size) - SOUND_SHM_SAMP_SIZE; + g_childsnd_pos = 0; + } + + reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, size); + + if(g_sound_paused) { + printf("Unpausing sound, zb: %d\n", g_zeroes_buffered); + g_sound_paused = 0; + } + + } else if((tmp >> 24) == 0xa1) { + if(g_sound_paused) { + if(g_zeroes_buffered < ZERO_PAUSE_SAFETY_SAMPS) { + g_zeroes_buffered += size; + } + } else { + /* not paused, send it through */ + g_zeroes_seen += size; + + reliable_zero_write(size); + + if(g_zeroes_seen >= ZERO_PAUSE_NUM_SAMPS) { + printf("Pausing sound\n"); + g_sound_paused = 1; + } + } + } else { + printf("tmp received bad: %08x\n", tmp); + exit(3); + } + + g_childsnd_pos += size; + while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { + g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; + } + + g_childsnd_vbl++; + if(g_childsnd_vbl >= 60) { + g_childsnd_vbl = 0; +#if 0 + printf("sound bytes written: %06x\n", g_bytes_written); + printf("Sample samples[0]: %08x %08x %08x %08x\n", + g_childsnd_shm_addr[0], g_childsnd_shm_addr[1], + g_childsnd_shm_addr[2], g_childsnd_shm_addr[3]); + printf("Sample samples[100]: %08x %08x %08x %08x\n", + g_childsnd_shm_addr[100], g_childsnd_shm_addr[101], + g_childsnd_shm_addr[102], g_childsnd_shm_addr[103]); +#endif + g_bytes_written = 0; + } +} + + +#ifdef HPUX +void +child_sound_init_hpdev() +{ + struct audio_describe audio_descr; + int output_channel; + char *str; + int speaker; + int ret; + int i; + + g_audio_socket = open("/dev/audio", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/audio failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_DESCRIBE, &audio_descr); + if(ret < 0) { + printf("ioctl AUDIO_DESCRIBE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + for(i = 0; i < audio_descr.nrates; i++) { + printf("Audio rate[%d] = %d\n", i, + audio_descr.sample_rate[i]); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_DATA_FORMAT, + AUDIO_FORMAT_LINEAR16BIT); + if(ret < 0) { + printf("ioctl AUDIO_SET_DATA_FORMAT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_CHANNELS, NUM_CHANNELS); + if(ret < 0) { + printf("ioctl AUDIO_SET_CHANNELS failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_TXBUFSIZE, 16*1024); + if(ret < 0) { + printf("ioctl AUDIO_SET_TXBUFSIZE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_SAMPLE_RATE, g_audio_rate); + if(ret < 0) { + printf("ioctl AUDIO_SET_SAMPLE_RATE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_GET_OUTPUT, &output_channel); + if(ret < 0) { + printf("ioctl AUDIO_GET_OUTPUT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + + speaker = 1; + str = getenv("SPEAKER"); + if(str) { + if(str[0] != 'i' && str[0] != 'I') { + speaker = 0; + } + } + + if(speaker) { + printf("Sending sound to internal speaker\n"); + output_channel |= AUDIO_OUT_SPEAKER; + } else { + printf("Sending sound to external jack\n"); + output_channel &= (~AUDIO_OUT_SPEAKER); + output_channel |= AUDIO_OUT_HEADPHONE; + } + + ret = ioctl(g_audio_socket, AUDIO_SET_OUTPUT, output_channel); + if(ret < 0) { + printf("ioctl AUDIO_SET_OUTPUT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } +} +#endif /* HPUX */ + +#ifdef SOLARIS +void +child_sound_init_solaris() +{ + struct audio_info audioi; + int ret; + + g_audio_socket = open("/dev/audio", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/audio failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_GETINFO, &audioi); + if(ret < 0) { + printf("ioctl audio getinfo ret: %d, errno:%d\n", ret, errno); + exit(1); + } + audioi.play.sample_rate = g_preferred_rate; + audioi.play.encoding = AUDIO_ENCODING_LINEAR; + audioi.play.precision = 16; + audioi.play.channels = 2; + ret = ioctl(g_audio_socket, AUDIO_SETINFO, &audioi); + if(ret < 0) { + printf("ioctl audio setinfo ret: %d, errno:%d\n", ret, errno); + exit(1); + } +} +#endif /* SOLARIS */ + +#if defined(__linux__) || defined(OSS) +void +child_sound_init_linux() +{ + int stereo; + int sample_size; + int rate; + int fragment; + int fmt; + int ret; + + g_audio_socket = open("/dev/dsp", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/dsp failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + fragment = 0x00200009; +#if 0 + ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFRAGMENT, &fragment); + if(ret < 0) { + printf("ioctl SETFRAGEMNT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } +#endif + + sample_size = 16; + ret = ioctl(g_audio_socket, SNDCTL_DSP_SAMPLESIZE, &sample_size); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SAMPLESIZE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + +#ifdef KEGS_LITTLE_ENDIAN + fmt = AFMT_S16_LE; +#else + fmt = AFMT_S16_BE; +#endif + ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFMT, &fmt); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SETFMT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + stereo = 1; + ret = ioctl(g_audio_socket, SNDCTL_DSP_STEREO, &stereo); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_STEREO failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + rate = g_audio_rate; + ret = ioctl(g_audio_socket, SNDCTL_DSP_SPEED, &rate); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SPEED failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + if(ret > 0) { + rate = ret; /* rate is returned value */ + } + if(rate < 8000) { + printf("Audio rate of %d which is < 8000!\n", rate); + exit(1); + } + + g_audio_rate = rate; + + printf("Sound initialized\n"); +} +#endif diff --git a/src/superhires.h b/src/superhires.h new file mode 100644 index 0000000..744010b --- /dev/null +++ b/src/superhires.h @@ -0,0 +1,204 @@ + +/* This file is included by video.c */ + +#ifndef SUPERHIRES_INCLUDED +const char rcsid_superhires_h[] = "@(#)$KmKId: superhires.h,v 1.9 2003-10-29 02:02:59-05 kentd Exp $"; +# define SUPERHIRES_INCLUDED +#endif + +void +SUPER_TYPE(byte *screen_data, int pixels_per_line, int y, int scan, + word32 ch_mask, int use_a2vid_palette, int mode_640) +{ + word32 *palptr; + word32 mem_ptr; + byte val0; + int x1, x2; + byte *b_ptr; + word32 *img_ptr, *img_ptr2; + word32 tmp, tmp2; + word32 ch_tmp; + byte *slow_mem_ptr; + int shift_per; + word32 pal; + word32 pal_word; + word32 pix0, pix1, pix2, pix3; + word32 save_pix; + int offset, next_line_offset; + int dopr; + + mem_ptr = 0xa0 * y + 0x12000; + tmp2 = 0; + tmp = 0; + + shift_per = (1 << SHIFT_PER_CHANGE); + if(use_a2vid_palette) { + pal = (g_a2vid_palette & 0xf); + } else { + pal = (scan & 0xf); + } + + if(SUPER_FILL) { + ch_mask = -1; + save_pix = 0; + } + + if(use_a2vid_palette) { + palptr = &(g_a2vid_palette_remap[0]); + } else { + palptr = &(g_palette_8to1624[pal * 16]); + } + + dopr = 0; +#if 0 + if(y == 1) { + dopr = 1; + printf("superhires line %d has ch_mask: %08x\n", y, ch_mask); + } +#endif + for(x1 = 0; x1 < 0xa0; x1 += shift_per) { + + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + pal_word = (pal << 28) + (pal << 20) + (pal << 12) + + (pal << 4); + + if(mode_640 && !use_a2vid_palette) { +#ifdef KEGS_LITTLE_ENDIAN + pal_word += 0x04000c08; +#else + pal_word += 0x080c0004; +#endif + } + + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + offset = y*2*pixels_per_line + x1*4; + next_line_offset = pixels_per_line; +#if SUPER_PIXEL_SIZE == 16 + offset *= 2; + next_line_offset *= 2; +#elif SUPER_PIXEL_SIZE == 32 + offset *= 4; + next_line_offset *= 4; +#endif + b_ptr = &screen_data[offset]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + next_line_offset); + + if(mode_640) { + for(x2 = 0; x2 < shift_per; x2++) { + val0 = *slow_mem_ptr++; + + pix0 = (val0 >> 6) & 0x3; + pix1 = (val0 >> 4) & 0x3; + pix2 = (val0 >> 2) & 0x3; + pix3 = val0 & 0x3; + if(use_a2vid_palette || (SUPER_PIXEL_SIZE > 8)){ + pix0 = palptr[pix0+8]; + pix1 = palptr[pix1+12]; + pix2 = palptr[pix2+0]; + pix3 = palptr[pix3+4]; + } +#if SUPER_PIXEL_SIZE == 8 +# ifdef KEGS_LITTLE_ENDIAN + tmp = (pix3 << 24) + (pix2 << 16) + + (pix1 << 8) + pix0 + pal_word; +# else + tmp = (pix0 << 24) + (pix1 << 16) + + (pix2 << 8) + pix3 + pal_word; +# endif + *img_ptr++ = tmp; *img_ptr2++ = tmp; +#elif SUPER_PIXEL_SIZE == 16 +# ifdef KEGS_LITTLE_ENDIAN + tmp = (pix1 << 16) + pix0; + tmp2 = (pix3 << 16) + pix2; +# else + tmp = (pix0 << 16) + pix1; + tmp2 = (pix2 << 16) + pix3; +# endif + *img_ptr++ = tmp; + *img_ptr++ = tmp2; + *img_ptr2++ = tmp; + *img_ptr2++ = tmp2; +#else /* SUPER_PIXEL_SIZE == 32 */ + *img_ptr++ = pix0; + *img_ptr++ = pix1; + *img_ptr++ = pix2; + *img_ptr++ = pix3; + *img_ptr2++ = pix0; + *img_ptr2++ = pix1; + *img_ptr2++ = pix2; + *img_ptr2++ = pix3; +#endif + +#if 0 + if(y == 1 && x1 == 0 && x2 == 0) { + printf("y==1,x1,x2=0, %02x = %08x %08x " + "%08x %08x, pal: %04x\n", val0, + pix0, pix1, pix2, pix3, pal); + printf("offset: %04x, nlo:%04x, ppl:" + "%04x, %d\n", offset, + next_line_offset, + pixels_per_line, SUPER_PIXEL_SIZE); + } +#endif + } + + } else { /* 320 mode */ + for(x2 = 0; x2 < shift_per; x2++) { + val0 = *slow_mem_ptr++; + pix0 = (val0 >> 4); + if(SUPER_FILL) { + if(pix0) { + save_pix = pix0; + } else { + pix0 = save_pix; + } + } + pix1 = (val0 & 0xf); + if(SUPER_FILL) { + if(pix1) { + save_pix = pix1; + } else { + pix1 = save_pix; + } + } + if(use_a2vid_palette || (SUPER_PIXEL_SIZE > 8)){ + pix0 = palptr[pix0]; + pix1 = palptr[pix1]; + } + if(dopr && x1 == 0) { + printf("y:%d, x2:%d, val:%02x = %08x %08x\n", y, x2, val0, pix0, pix1); + } +#if SUPER_PIXEL_SIZE == 8 +# ifdef KEGS_LITTLE_ENDIAN + tmp = (pix1 << 24) + (pix1 << 16) + + (pix0 << 8) + pix0 + pal_word; +# else + tmp = (pix0 << 24) + (pix0 << 16) + + (pix1 << 8) + pix1 + pal_word; +# endif + *img_ptr++ = tmp; *img_ptr2++ = tmp; +#elif SUPER_PIXEL_SIZE == 16 + tmp = (pix0 << 16) + pix0; + tmp2 = (pix1 << 16) + pix1; + *img_ptr++ = tmp; + *img_ptr++ = tmp2; + *img_ptr2++ = tmp; + *img_ptr2++ = tmp2; +#else /* SUPER_PIXEL_SIZE == 32 */ + *img_ptr++ = pix0; + *img_ptr++ = pix0; + *img_ptr++ = pix1; + *img_ptr++ = pix1; + *img_ptr2++ = pix0; + *img_ptr2++ = pix0; + *img_ptr2++ = pix1; + *img_ptr2++ = pix1; +#endif + } + } + } +} + diff --git a/src/to_pro.c b/src/to_pro.c new file mode 100755 index 0000000..722c333 --- /dev/null +++ b/src/to_pro.c @@ -0,0 +1,897 @@ +/****************************************************************/ +/* Apple //gs emulator */ +/* Copyright 1996 Kent Dickey */ +/* */ +/* This code may not be used in a commercial product */ +/* without prior written permission of the author. */ +/* */ +/* You may freely distribute this code. */ +/* */ +/* You can contact the author at kentd@cup.hp.com. */ +/* HP has nothing to do with this software. */ +/****************************************************************/ + +#include "defc.h" +#include + +#include "prodos.h" + +#include + + +#define DEF_DISK_SIZE (800*1024) +#define MAX_FILE_NAMES 51 + +char out_name[] = "POOF1"; + +int g_def_file_type = -1; +int g_def_aux_type = -1; + +void make_legal_prodos_name(char *new_name, char *old_name); + +int +main(int argc, char **argv) +{ + char *files[MAX_FILE_NAMES]; + char *name; + char *new_name_end; + int new_name_len; + struct stat stat_buf; + int in; + int in_size; + int ret; + ProDisk *disk; + char new_name[128]; + byte in_buf[1024]; + int disk_size; + int i; + int done; + int pos; + int size; + int num_files; + int file_type; + int aux_type; + + disk_size = DEF_DISK_SIZE; + if(argc < 2) { + fprintf(stderr, "%s: {-[size in K]} {unix_files}\n", + argv[0]); + exit(1); + } + + num_files = 0; + for(i = 1; i < argc; i++) { + if(argv[i][0] == '-') { + /* I smell a -size_in_K */ + disk_size = strtoul(&(argv[i][1]), 0, 10) * 1024; + printf("disk_size: %d, 0x%x\n", disk_size, disk_size); + if(disk_size < 40*1024) { + printf("Too small!\n"); + exit(1); + } + } else { + files[num_files] = argv[i]; + num_files++; + if(num_files >= MAX_FILE_NAMES) { + printf("Too many filenames: %d\n", num_files); + exit(2); + } + } + } + + disk = allocate_memdisk(out_name, disk_size); + format_memdisk(disk, out_name); + + for(i = 0; i < num_files; i++) { + name = files[i]; + in = open(name, O_RDONLY | O_BINARY); + if(in < 0) { + fprintf(stderr, "opening %s returned %d, errno: %d\n", + name, in, errno); + exit(1); + } + + ret = fstat(in, &stat_buf); + if(ret != 0) { + fprintf(stderr, "fstat returned %d, errno: %d\n", + ret, errno); + } + + in_size = stat_buf.st_size; + printf("in size: %d\n", in_size); + + if(in_size > disk->disk_bytes_left) { + printf("File bigger than %d, too big!\n", disk_size); + exit(2); + } + + make_legal_prodos_name(new_name, name); + + new_name_len = strlen(new_name); + new_name_end = new_name + new_name_len; + + file_type = g_def_file_type; + aux_type = g_def_aux_type; + while(g_def_file_type < 0) { + /* choose file type */ + if(new_name_len >= 5) { + if(strcmp(new_name_end - 4, ".SHK") == 0) { + file_type = 0xe0; + aux_type = 0x8002; + break; + } + if(strcmp(new_name_end - 4, ".SDK") == 0) { + file_type = 0xe0; + aux_type = 0x8002; + break; + } + } + file_type = 0x04; /* TXT */ + aux_type = 0; + break; + } + + create_new_file(disk, 2, 1, new_name, file_type, + 0, 0, 0, 0xc3, aux_type, 0, in_size); + + + done = 0; + pos = 0; + while(pos < in_size) { + size = 512; + if(pos + size > in_size) { + size = in_size - pos; + } + ret = read(in, in_buf, size); + if(ret != size || ret <= 0) { + fprintf(stderr, "read returned %d, errno: %d\n", + ret, errno); + exit(2); + } + ret = pro_write_file(disk, in_buf, pos, size); + if(ret != 0) { + printf("pro_write returned %d!\n", ret); + exit(3); + } + pos += size; + } + + close_file(disk); + + close(in); + } + + flush_disk(disk); + return 0; +} + +void +make_legal_prodos_name(char *new_name, char *old_name) +{ + char *ptr; + int start_len, start_char; + int len; + int pos; + int c; + int j; + + for(j = 0; j < 16; j++) { + /* make sure it ends with null == 15 + 1 */ + new_name[j] = 0; + } + + start_char = 0; + start_len = strlen(old_name); + len = 0; + ptr = &old_name[start_len - 1]; + for(j = start_len - 1; j >= 0; j--) { + if(*ptr == '/' || *ptr == ':') { + break; + } + ptr--; + len++; + } + ptr++; + + if(len <= 0) { + printf("Filename: %s has len: %d!\n", old_name, len); + exit(1); + } + + printf("mid_name: %s, len:%d\n", ptr, len); + + pos = 0; + for(j = 0; j < 15; j++) { + c = ptr[pos]; + if(isalnum(c)) { + c = toupper(c); + } else if(c != 0) { + c = '.'; + } + + if(j == 0 && !isalpha(c)) { + c = 'A'; + } + + new_name[j] = c; + + pos++; + if(pos == 7 && len > 15) { + pos = len - 8; + } + } + + printf("new_name: %s\n", new_name); +} + +void +flush_disk(ProDisk *disk) +{ + disk_write_data(disk, 6, disk->bitmap_ptr, + disk->size_bitmap_blocks * 512); + close(disk->fd); + disk->fd = -1; +} + +void +close_file(ProDisk *disk) +{ + write_ind_block(disk); + write_master_ind_block(disk); + disk_write_data(disk, disk->dir_blk_num, &(disk->dir_blk_data[0]), 512); + disk->file_ptr = 0; +} + +ProDisk * +allocate_memdisk(char *out_name, int size) +{ + ProDisk *disk; + int out; + + out = open(out_name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0x1b6); + if(out < 0) { + fprintf(stderr, "opening %s returned %d, errno: %d\n", + out_name, out, errno); + exit(1); + } + + disk = (ProDisk *)malloc(sizeof(ProDisk)); + if(disk == 0) { + printf("allocate_memdisk failed, errno: %d\n", errno); + } + + disk->fd = out; + disk->total_blocks = (size + 511) / 512; + disk->bitmap_ptr = 0; + disk->disk_bytes_left = 0; + disk->size_bitmap_blocks = 0; + disk->dir_blk_num = -1; + disk->ind_blk_num = -1; + disk->master_ind_blk_num = -1; + + return disk; +} + +void +format_memdisk(ProDisk *disk, char *name) +{ + byte zero_buf[1024]; + int total_blocks; + byte *bitmap_ptr; + Vol_hdr *vol_hdr; + Directory *dir; + int size_bitmap_bytes; + int size_bitmap_blocks; + int disk_blocks_left; + int i, j; + + total_blocks = disk->total_blocks; + + /* Zero out blocks 0 and 1 */ + for(i = 0; i < 2*512; i++) { + zero_buf[i] = 0; + } + disk_write_data(disk, 0x00000, zero_buf, 2*512); + + /* and make the image the right size */ + disk_write_data(disk, total_blocks - 1, zero_buf, 512); + + dir = disk_read_dir(disk, 2); + set_l2byte(&(dir->prev_blk), 0); + set_l2byte(&(dir->next_blk), 3); + vol_hdr = (Vol_hdr *)&(dir->file_entries[0]); + vol_hdr->storage_type_name_len = 0xf0 + strlen(name); + strncpy((char *)vol_hdr->vol_name, name, strlen(name)); + vol_hdr->version = 0; + vol_hdr->min_version = 0; + vol_hdr->access = 0xc3; + vol_hdr->entry_length = 0x27; + vol_hdr->entries_per_block = 0x0d; + set_l2byte(&(vol_hdr->file_count), 0); + vol_hdr->entries_per_block = 0x0d; + set_l2byte(&(vol_hdr->bit_map), 6); + set_l2byte(&(vol_hdr->total_blocks), total_blocks); + for(i = 1; i < 13; i++) { + set_file_entry(&(dir->file_entries[i]), 0, "", 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0); + } + disk_write_dir(disk, 2); + + + for(i = 3; i < 6; i++) { + dir = disk_read_dir(disk, i); + set_l2byte(&(dir->prev_blk), i - 1); + set_l2byte(&(dir->next_blk), i + 1); + if(i == 5) { + set_l2byte(&(dir->next_blk), 0); + } + for(j = 0; j < 13; j++) { + set_file_entry(&(dir->file_entries[j]), 0, "", 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0); + } + + disk_write_dir(disk, i); + } + + size_bitmap_bytes = (total_blocks + 7)/ 8; + size_bitmap_blocks = (size_bitmap_bytes + 511)/ 512; + bitmap_ptr = (byte *)malloc(size_bitmap_blocks * 512); + for(i = 0; i < 6+size_bitmap_blocks; i++) { + set_bitmap_used(bitmap_ptr, i); + } + for(i = 6+size_bitmap_blocks; i < total_blocks; i++) { + set_bitmap_free(bitmap_ptr, i); + } + for(i = total_blocks; i < size_bitmap_blocks*512*8; i++) { + set_bitmap_used(bitmap_ptr, i); + } + + disk_write_data(disk, 6, bitmap_ptr, size_bitmap_blocks * 512); + disk->bitmap_ptr = bitmap_ptr; + disk->size_bitmap_blocks = size_bitmap_blocks; + disk->bitmap_bytes = size_bitmap_blocks * 512; + disk->bitmap_cur_pos = 0; + + disk_blocks_left = total_blocks - 6 - size_bitmap_blocks; + disk->disk_bytes_left = disk_blocks_left * 512; +} + +void +disk_write_data(ProDisk *disk, int blk_num, byte *buf, int size) +{ + int size_in_blocks; + int ret; + +#if 0 + printf("Writing blk %04x from buf: %08x, %03x\n", blk_num, buf, size); +#endif + + size_in_blocks = size >> 9; + if(size_in_blocks * 512 != size) { + printf("disk_write: blk: %04x, buf: %08x, size: %08x\n", + blk_num, (word32)buf, size); + exit(1); + } + + ret = lseek(disk->fd, 512*blk_num, SEEK_SET); + if(ret != 512*blk_num) { + printf("disk_write: seek: %d, errno: %d, blk: %04x, buf: " + "%08x, sz: %08x\n", ret, errno, blk_num, + (word32)buf, size); + exit(1); + } + + ret = write(disk->fd, buf, size); + if(ret != size) { + printf("disk_write: write: %d, errno: %d, blk: %04x, buf: " + "%08x, sz: %08x\n", ret, errno, blk_num, + (word32)buf, size); + exit(1); + } +} + +void +disk_read_data(ProDisk *disk, int blk_num, byte *buf, int size) +{ + int size_in_blocks; + int ret; + int i; + + size_in_blocks = size >> 9; + if(size_in_blocks * 512 != size) { + printf("disk_read: blk: %04x, buf: %08x, size: %08x\n", + blk_num, (word32)buf, size); + exit(1); + } + + ret = lseek(disk->fd, 512*blk_num, SEEK_SET); + if(ret != 512*blk_num) { + printf("disk_read: seek: %d, errno: %d, blk: %04x, buf: " + "%08x, sz: %08x\n", ret, errno, blk_num, + (word32)buf, size); + exit(1); + } + + ret = read(disk->fd, buf, size); + if(ret != size) { + printf("disk_read: read: %d, errno: %d, blk: %04x, buf: " + "%08x, sz: %08x\n", ret, errno, blk_num, + (word32)buf, size); + for(i = 0; i < size; i++) { + buf[i] = 0; + } + } +} + +Directory * +disk_read_dir(ProDisk *disk, int blk_num) +{ + disk_write_dir(disk, blk_num); + + disk->dir_blk_num = blk_num; + disk_read_data(disk, blk_num, &(disk->dir_blk_data[0]), 512); + + return (Directory *)&(disk->dir_blk_data[0]); +} + +void +disk_write_dir(ProDisk *disk, int blk_num) +{ + if(disk->dir_blk_num >= 0) { + if(disk->dir_blk_num != blk_num) { + printf("disk_write_dir: %04x != %04x\n", + disk->dir_blk_num, blk_num); + } + disk_write_data(disk, disk->dir_blk_num, + &(disk->dir_blk_data[0]), 512); + disk->dir_blk_num = -1; + } +} + +void +create_new_file(ProDisk *disk, int dir_block, int storage_type, char *name, + int file_type, word32 creation_time, int version, int min_version, + int access, int aux_type, word32 last_mod, word32 eof) +{ + Vol_hdr *vol_ptr; + int val; + Directory *dir_ptr; + File_entry *file_ptr; + int file_count; + int pos; + int last_pos; + int done; + int next_blk; + int name_len; + + name_len = strlen(name); + dir_ptr = disk_read_dir(disk, dir_block); + next_blk = dir_block; + val = dir_ptr->file_entries[0].storage_type_name_len; + last_pos = 13; + pos = 0; + if(((val & 0xf0) == 0xf0) || ((val & 0xf0) == 0xe0)) { + /* vol dir or subdir header */ + vol_ptr = (Vol_hdr *)&(dir_ptr->file_entries[0]); + file_count = get_l2byte(&(vol_ptr->file_count)); + pos = 1; + last_pos = vol_ptr->entries_per_block; + } else { + printf("dir_block: %04x not subdir or voldir\n", dir_block); + exit(6); + } + + vol_ptr = 0; + + done = 0; + while(!done) { + file_ptr = &(dir_ptr->file_entries[pos]); + if(((file_ptr->storage_type_name_len) & 0xf0) == 0) { + /* Got it! */ + file_ptr->storage_type_name_len = + (storage_type << 4) | name_len; + strncpy((char *)file_ptr->file_name, name, 15); + file_ptr->file_type = file_type; + set_l2byte(&(file_ptr->key_pointer), + find_next_free_block(disk)); + set_l2byte(&(file_ptr->blocks_used), 0); + set_pro_time(&(file_ptr->creation_time), + creation_time); + file_ptr->version = version; + file_ptr->min_version = min_version; + file_ptr->access = access; + set_l2byte(&(file_ptr->aux_type), aux_type); + set_pro_time(&(file_ptr->last_mod), last_mod); + set_l2byte(&(file_ptr->header_pointer), + dir_block); + set_l3byte(&(file_ptr->eof), eof); + disk_write_dir(disk, next_blk); + + dir_ptr = disk_read_dir(disk, dir_block); + vol_ptr = (Vol_hdr *)&(dir_ptr->file_entries[0]); + set_l2byte(&(vol_ptr->file_count), file_count+1); + disk_write_dir(disk, dir_block); + + disk_read_dir(disk, next_blk); + /* re-read dir so that ptrs are set up right */ + disk->file_ptr = file_ptr; + disk->file_open = 1; + disk->ind_blk_num = -1; + disk->master_ind_blk_num = -1; + done = 1; + break; + } else { + /* check to make sure name is unique */ + if((file_ptr->storage_type_name_len & 0x0f)== name_len){ + if(!memcmp(file_ptr->file_name, name,name_len)){ + printf("Name %s already on disk!\n", + name); + exit(8); + } + } + pos++; + if(pos >= last_pos) { + /* Go to next block */ + next_blk = get_l2byte(&(dir_ptr->next_blk)); + if(next_blk) { + dir_ptr = disk_read_dir(disk, next_blk); + pos = 0; + } else { + printf("Top directory full!\n"); + exit(2); + } + } + } + } +} + +int +pro_write_file(ProDisk *disk, byte *in_buf, int pos, int size) +{ + int block; + int i; + + block = get_disk_block(disk, pos, 1); + if(block < 7) { + printf("pro_write_file, get_disk_block: %d\n", block); + exit(3); + } + if(size < 512) { + for(i = size; i < 512; i++) { + in_buf[i] = 0; + } + } else if(size > 512) { + printf("error, pro_write_file size: %d too big\n", size); + exit(4); + } + + disk_write_data(disk, block, in_buf, 512); + + return 0; +} + + + +int +get_disk_block(ProDisk *disk, int pos, int create) +{ + File_entry *file_ptr; + int storage_type; + word32 eof; + int lo, hi; + int offset; + int master_ind_block, ind_block; + int ret_block; + int key_block; + + if(pos >= 128*256*512) { + printf("offset too big\n"); + exit(3); + } + + file_ptr = disk->file_ptr; + + eof = get_l3byte(&(file_ptr->eof)); + storage_type = (file_ptr->storage_type_name_len) >> 4; + + key_block = get_l2byte(&(file_ptr->key_pointer)); + + if(storage_type == 1 && pos >= 512) { + /* make it sapling */ + get_new_ind_block(disk); + inc_l2byte(&(file_ptr->blocks_used)); + disk->ind_blk_data[0] = key_block & 0xff; + disk->ind_blk_data[0x100] = key_block >> 8; + key_block = disk->ind_blk_num; + set_l2byte(&(file_ptr->key_pointer), key_block); + file_ptr->storage_type_name_len += 0x10; + storage_type++; + } + if(storage_type == 2 && pos >= 256*512) { + /* make it tree */ + get_new_master_ind_block(disk); + inc_l2byte(&(file_ptr->blocks_used)); + disk->master_ind_blk_data[0] = key_block & 0xff; + disk->master_ind_blk_data[0x100] = key_block >> 8; + key_block = disk->master_ind_blk_num; + set_l2byte(&(file_ptr->key_pointer), key_block); + file_ptr->storage_type_name_len += 0x10; + storage_type++; + } + + switch(storage_type) { + case 1: + if(pos >= 512) { + printf("Error1!\n"); + exit(3); + } + ret_block = key_block; + if(ret_block == 0) { + ret_block = find_next_free_block(disk); + inc_l2byte(&(file_ptr->blocks_used)); + set_l2byte(&(file_ptr->key_pointer), ret_block); + } + return ret_block; + case 2: + ind_block = key_block; + if(ind_block <= 0) { + printf("write failure, ind_block: %d!\n", ind_block); + exit(3); + } + offset = pos >> 9; + if(offset >= 256) { + printf("pos too big!\n"); + exit(3); + } + + lo = disk->ind_blk_data[offset]; + hi = disk->ind_blk_data[offset + 0x100]; + ret_block = hi*256 + lo; + if(ret_block == 0) { + /* Need to alloc a block for this guy */ + ret_block = find_next_free_block(disk); + inc_l2byte(&(file_ptr->blocks_used)); + disk->ind_blk_data[offset] = ret_block & 0xff; + disk->ind_blk_data[offset + 0x100] = + ((ret_block >> 8) & 0xff); + } + return ret_block; + case 3: + /* tree */ + master_ind_block = key_block; + if(master_ind_block <= 0) { + printf("write failure, master_ind_block: %d!\n", + master_ind_block); + exit(3); + } + offset = pos >> 17; + if(offset >= 128) { + printf("master too big!\n"); + exit(4); + } + lo = disk->master_ind_blk_data[offset]; + hi = disk->master_ind_blk_data[offset + 0x100]; + ind_block = hi*256 + lo; + if(ind_block == 0) { + /* Need to alloc an ind block */ + get_new_ind_block(disk); + ind_block = disk->ind_blk_num; + inc_l2byte(&(file_ptr->blocks_used)); + disk->master_ind_blk_data[offset] = ind_block & 0xff; + disk->master_ind_blk_data[offset + 0x100] = + ((ind_block >> 8) & 0xff); + } + + offset = (pos >> 9) & 0xff; + lo = disk->ind_blk_data[offset]; + hi = disk->ind_blk_data[offset + 0x100]; + ret_block = hi*256 + lo; + + if(ret_block == 0) { + /* Need to alloc a block for this guy */ + ret_block = find_next_free_block(disk); + inc_l2byte(&(file_ptr->blocks_used)); + disk->ind_blk_data[offset] = ret_block & 0xff; + disk->ind_blk_data[offset + 0x100] = + ((ret_block >> 8) & 0xff); + } + return ret_block; + default: + printf("unknown storage type: %d\n", storage_type); + exit(4); + } + + printf("Can't get here!\n"); + exit(5); +} + +void +get_new_ind_block(ProDisk *disk) +{ + int ind_blk_num; + int i; + + write_ind_block(disk); + + ind_blk_num = find_next_free_block(disk); + for(i = 0; i < 512; i++) { + disk->ind_blk_data[i] = 0; + } + + disk->ind_blk_num = ind_blk_num; +} + +void +write_ind_block(ProDisk *disk) +{ + int ind_blk_num; + + ind_blk_num = disk->ind_blk_num; + if(ind_blk_num > 0) { + printf("Write ind block: %04x\n", ind_blk_num); + disk_write_data(disk, ind_blk_num, &(disk->ind_blk_data[0]), + 512); + disk->ind_blk_num = -1; + } +} + +void +get_new_master_ind_block(ProDisk *disk) +{ + int master_ind_blk_num; + int i; + + write_master_ind_block(disk); + + master_ind_blk_num = find_next_free_block(disk); + for(i = 0; i < 512; i++) { + disk->master_ind_blk_data[i] = 0; + } + + disk->master_ind_blk_num = master_ind_blk_num; +} + +void +write_master_ind_block(ProDisk *disk) +{ + int master_ind_blk_num; + + master_ind_blk_num = disk->master_ind_blk_num; + if(master_ind_blk_num > 0) { + printf("Write master_ind block: %04x\n", master_ind_blk_num); + disk_write_data(disk, master_ind_blk_num, + &(disk->master_ind_blk_data[0]), 512); + disk->master_ind_blk_num = -1; + } +} + +int +find_next_free_block(ProDisk *disk) +{ + byte *bitmap_ptr; + int pos; + int bitmap_bytes; + int i, j; + word32 val; + + bitmap_ptr = disk->bitmap_ptr; + bitmap_bytes = disk->bitmap_bytes; + pos = disk->bitmap_cur_pos; + + for(i = pos; i < bitmap_bytes; i++) { + val = bitmap_ptr[i]; + if(val == 0) { + continue; + } + for(j = 0; j < 8; j++) { + if(val & (0x80 >> j)) { + set_bitmap_used(bitmap_ptr, 8*i+j); + disk->bitmap_cur_pos = i; + return 8*i + j; + } + } + return -1; + } + return -1; +} + + + +void +set_bitmap_used(byte *ptr, int i) +{ + word32 offset, bit; + word32 val; + + offset = i >> 3; + bit = i & 7; + + val = ~(0x80 >> bit); + ptr[offset] &= val; +} + +void +set_bitmap_free(byte *ptr, int i) +{ + int offset, bit; + int val; + + offset = i >> 3; + bit = i & 7; + + val = (0x80 >> bit); + ptr[offset] |= val; +} + +void +set_file_entry(File_entry *entry, int storage_type_name_len, char *file_name, + int file_type, int key_pointer, int blocks_used, int eof, + word32 creation_time, int version, int min_version, int access, + int aux_type, word32 last_mod, int header_pointer) +{ + + entry->storage_type_name_len = storage_type_name_len; + strncpy((char *)entry->file_name, file_name, 15); + entry->file_type = file_type; + set_l2byte(&(entry->key_pointer), key_pointer); + set_l2byte(&(entry->blocks_used), blocks_used); + set_l3byte(&(entry->eof), eof); + set_pro_time(&(entry->creation_time), creation_time); + entry->version = version; + entry->min_version = min_version; + entry->access = access; + set_l2byte(&(entry->aux_type), aux_type); + set_pro_time(&(entry->last_mod), last_mod); + set_l2byte(&(entry->aux_type), header_pointer); + +} + +void +set_l2byte(L2byte *ptr, int val) +{ + ptr->low = (val & 0xff); + ptr->hi = ((val >> 8) & 0xff); + +} + +void +set_l3byte(L3byte *ptr, int val) +{ + ptr->low = (val & 0xff); + ptr->hi = ((val >> 8) & 0xff); + ptr->higher = ((val >> 16) & 0xff); + +} + +void +set_pro_time(Pro_time *ptr, word32 val) +{ + ptr->times[0] = ((val >> 24) & 0xff); + ptr->times[1] = ((val >> 16) & 0xff); + ptr->times[2] = ((val >> 8) & 0xff); + ptr->times[3] = ((val) & 0xff); +} + +int +get_l2byte(L2byte *ptr) +{ + int val; + + val = ((ptr->hi) * 256) + ptr->low; + return val; +} + +int +get_l3byte(L3byte *ptr) +{ + int val; + + val = ((ptr->higher) * 65536) + ((ptr->hi) * 256) + ptr->low; + return val; +} + +void +inc_l2byte(L2byte *ptr) +{ + set_l2byte(ptr, get_l2byte(ptr) + 1); +} diff --git a/src/vars b/src/vars new file mode 120000 index 0000000..aa40ff6 --- /dev/null +++ b/src/vars @@ -0,0 +1 @@ +vars_mac \ No newline at end of file diff --git a/src/vars_c b/src/vars_c new file mode 100644 index 0000000..a896f13 --- /dev/null +++ b/src/vars_c @@ -0,0 +1,20 @@ + +TARGET = xkegs +OBJECTS = $(OBJECTS1) xdriver.o +CC = gcc +CCOPTS = -O +OPTS = -DNDEBUG +SUFFIX = +NAME = xkegs +LDFLAGS = +LDOPTS = -z +LD = $(CC) +EXTRA_LIBS = -lXext -lX11 -lcl -lc +EXTRA_SPECIALS = Alib.h + +AS = cc -Ae +PERL = perl + +XOPTS = -DHPUX -I/usr/include/X11R5 +XLIBS = -L/usr/lib/X11R5 -L/opt/audio/lib + diff --git a/src/vars_hp b/src/vars_hp new file mode 100644 index 0000000..a1c5d84 --- /dev/null +++ b/src/vars_hp @@ -0,0 +1,20 @@ + +TARGET = xkegs +OBJECTS = engine_s.o $(OBJECTS1) sound_driver.o xdriver.o +CC = cc -Ae +DA1.1 +CCOPTS = -O +OPTS = -DNDEBUG +SUFFIX = +NAME = xkegs +LDFLAGS = +LDOPTS = -z +LD = $(CC) +EXTRA_LIBS = -lXext -lX11 -lcl -lc +EXTRA_SPECIALS = 8inst_s 16inst_s 8size 16size size_s Alib.h + +AS = cc -Ae +PERL = perl + +XOPTS = -DHPUX -I/usr/include/X11R5 +XLIBS = -L/usr/lib/X11R5 -L/opt/audio/lib + diff --git a/src/vars_linuxppc b/src/vars_linuxppc new file mode 100644 index 0000000..996274c --- /dev/null +++ b/src/vars_linuxppc @@ -0,0 +1,20 @@ + +TARGET = xkegs +OBJECTS = $(OBJECTS1) xdriver.o +CC = cc +CCOPTS = -O +OPTS = -DNDEBUG +SUFFIX = +NAME = xkegs +LDFLAGS = +LDOPTS = +LD = $(CC) +EXTRA_LIBS = -lXext -lX11 -lc +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X11R6/include +XLIBS = -L/usr/X11R6/lib + diff --git a/src/vars_mac b/src/vars_mac new file mode 100644 index 0000000..d59fed2 --- /dev/null +++ b/src/vars_mac @@ -0,0 +1,10 @@ + +TARGET = kegsmac +OBJECTS = $(OBJECTS1) macsnd_driver.o macdriver.o +CCOPTS = -O2 -DMAC +SUFFIX = +NAME = kegsmac + +XOPTS = -Wall -fpascal-strings -mdynamic-no-pic -arch ppc +XLIBS = + diff --git a/src/vars_solaris b/src/vars_solaris new file mode 100644 index 0000000..4b77f20 --- /dev/null +++ b/src/vars_solaris @@ -0,0 +1,20 @@ + +TARGET = xkegs +OBJECTS = $(OBJECTS1) xdriver.o +CC = cc +CCOPTS = -O +OPTS = -DNDEBUG -DSOLARIS +SUFFIX = +NAME = xkegs +LDFLAGS = +LDOPTS = +LD = $(CC) +EXTRA_LIBS = -lXext -lX11 -lsocket -lnsl +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X/include +XLIBS = -L/usr/X/lib + diff --git a/src/vars_win32 b/src/vars_win32 new file mode 100644 index 0000000..ac61f66 --- /dev/null +++ b/src/vars_win32 @@ -0,0 +1,10 @@ + +TARGET = kegswin.exe +OBJECTS = $(OBJECTS1) win32snd_driver.o windriver.o +CCOPTS = -O2 -DKEGS_LITTLE_ENDIAN +SUFFIX = ".exe" +NAME = kegswin + +XOPTS = -Wall -fomit-frame-pointer -march=pentium +XLIBS = + diff --git a/src/vars_x86linux b/src/vars_x86linux new file mode 100644 index 0000000..c99e999 --- /dev/null +++ b/src/vars_x86linux @@ -0,0 +1,19 @@ + +TARGET = xkegs +OBJECTS = $(OBJECTS1) xdriver.o +CC = cc +CCOPTS = -O2 -Wall -fomit-frame-pointer -march=pentium +OPTS = -DKEGS_LITTLE_ENDIAN +SUFFIX = +NAME = xkegs +LDFLAGS = +LDOPTS = +LD = $(CC) +EXTRA_LIBS = -lXext +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X11R6/include + diff --git a/src/vars_x86solaris b/src/vars_x86solaris new file mode 100644 index 0000000..69d8671 --- /dev/null +++ b/src/vars_x86solaris @@ -0,0 +1,20 @@ + +TARGET = xkegs +OBJECTS = $(OBJECTS1) xdriver.o +CC = gcc +CCOPTS = -O +OPTS = -DNDEBUG -DSOLARIS -DKEGS_LITTLE_ENDIAN -DOSS +SUFFIX = +NAME = xkegs +LDFLAGS = +LDOPTS = +LD = $(CC) +EXTRA_LIBS = -lXext -lX11 -lsocket -lnsl +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X/include +XLIBS = -L/usr/X/lib + diff --git a/src/video.c b/src/video.c new file mode 100644 index 0000000..b7a4055 --- /dev/null +++ b/src/video.c @@ -0,0 +1,3354 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_video_c[] = "@(#)$KmKId: video.c,v 1.125 2004-03-23 17:25:50-05 kentd Exp $"; + +#include + +#include "defc.h" + +extern int Verbose; + +int g_a2_line_stat[200]; +int g_a2_line_left_edge[200]; +int g_a2_line_right_edge[200]; +Kimage *g_a2_line_kimage[200]; + +int g_mode_text[2][200]; +int g_mode_hires[2][200]; +int g_mode_superhires[200]; +int g_mode_border[200]; + +byte g_cur_border_colors[270]; +byte g_new_special_border[64][64]; +byte g_cur_special_border[64][64]; + +word32 g_a2_screen_buffer_changed = (word32)-1; +word32 g_full_refresh_needed = (word32)-1; + +word32 g_cycs_in_40col = 0; +word32 g_cycs_in_xredraw = 0; +word32 g_refresh_bytes_xfer = 0; + +extern byte *g_slow_memory_ptr; +extern int g_screen_depth; +extern int g_screen_mdepth; + +extern int statereg; +extern double g_cur_dcycs; + +extern int g_line_ref_amt; + +extern int g_border_color; +extern int g_config_control_panel; + +typedef byte Change; + +word32 slow_mem_changed[SLOW_MEM_CH_SIZE]; + +word32 g_font40_even_bits[0x100][8][16/4]; +word32 g_font40_odd_bits[0x100][8][16/4]; +word32 g_font80_off0_bits[0x100][8][12/4]; +word32 g_font80_off1_bits[0x100][8][12/4]; +word32 g_font80_off2_bits[0x100][8][12/4]; +word32 g_font80_off3_bits[0x100][8][12/4]; + +word32 g_superhires_scan_save[256]; + +Kimage g_kimage_text[2]; +Kimage g_kimage_hires[2]; +Kimage g_kimage_superhires; +Kimage g_kimage_border_special; +Kimage g_kimage_border_sides; + +Kimage g_mainwin_kimage; + +extern double g_last_vbl_dcycs; + +int g_need_redraw = 1; +int g_palette_change_summary = 0; +word32 g_palette_change_cnt[16]; +int g_border_sides_refresh_needed = 1; +int g_border_special_refresh_needed = 1; +int g_border_line24_refresh_needed = 1; +int g_status_refresh_needed = 1; + +int g_vbl_border_color = 0; +int g_border_last_vbl_changes = 0; + +int g_use_dhr140 = 0; +int g_use_bw_hires = 0; + +int g_a2_new_all_stat[200]; +int g_a2_cur_all_stat[200]; +int g_new_a2_stat_cur_line = 0; +int g_vid_update_last_line = 0; + +int g_expanded_col_0[16]; +int g_expanded_col_1[16]; +int g_expanded_col_2[16]; + + +int g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR); + +int g_a2vid_palette = 0xe; +int g_installed_full_superhires_colormap = 0; + +int Max_color_size = 256; + +word32 g_palette_8to1624[256]; +word32 g_a2palette_8to1624[256]; + +word32 g_saved_line_palettes[200][8]; +int g_saved_a2vid_palette = -1; +word32 g_a2vid_palette_remap[16]; + +word32 g_cycs_in_refresh_line = 0; +word32 g_cycs_in_refresh_ximage = 0; + +int g_num_lines_superhires = 0; +int g_num_lines_superhires640 = 0; +int g_num_lines_prev_superhires = 0; +int g_num_lines_prev_superhires640 = 0; + +word32 g_red_mask = 0xff; +word32 g_green_mask = 0xff; +word32 g_blue_mask = 0xff; +int g_red_left_shift = 16; +int g_green_left_shift = 8; +int g_blue_left_shift = 0; +int g_red_right_shift = 0; +int g_green_right_shift = 0; +int g_blue_right_shift = 0; + +char g_status_buf[MAX_STATUS_LINES][STATUS_LINE_LENGTH + 1]; +char *g_status_ptrs[MAX_STATUS_LINES] = { 0 }; + +const int g_dbhires_colors[] = { + /* rgb */ + 0x000, /* 0x0 black */ + 0xd03, /* 0x1 deep red */ + 0x852, /* 0x2 brown */ + 0xf60, /* 0x3 orange */ + 0x070, /* 0x4 dark green */ + 0x555, /* 0x5 dark gray */ + 0x0d0, /* 0x6 green */ + 0xff0, /* 0x7 yellow */ + 0x009, /* 0x8 dark blue */ + 0xd0d, /* 0x9 purple */ + 0xaaa, /* 0xa light gray */ + 0xf98, /* 0xb pink */ + 0x22f, /* 0xc medium blue */ + 0x6af, /* 0xd light blue */ + 0x0f9, /* 0xe aquamarine */ + 0xfff /* 0xf white */ +}; + +word32 g_dhires_convert[4096]; /* look up table of 7 bits (concat): */ + /* { 4 bits, |3 prev bits| } */ + +const byte g_dhires_colors_16[] = { + 0x00, /* 0x0 black */ + 0x02, /* 0x1 dark blue */ + 0x04, /* 0x2 dark green */ + 0x06, /* 0x3 medium blue */ + 0x08, /* 0x4 brown */ + 0x0a, /* 0x5 light gray */ + 0x0c, /* 0x6 green */ + 0x0e, /* 0x7 aquamarine */ + 0x01, /* 0x8 deep red */ + 0x03, /* 0x9 purple */ + 0x05, /* 0xa dark gray */ + 0x07, /* 0xb light blue */ + 0x09, /* 0xc orange */ + 0x0b, /* 0xd pink */ + 0x0d, /* 0xe yellow */ + 0x0f/* 0xf white */ +}; + +const int g_lores_colors[] = { + /* rgb */ + 0x000, /* 0x0 black */ + 0xd03, /* 0x1 deep red */ + 0x009, /* 0x2 dark blue */ + 0xd0d, /* 0x3 purple */ + 0x070, /* 0x4 dark green */ + 0x555, /* 0x5 dark gray */ + 0x22f, /* 0x6 medium blue */ + 0x6af, /* 0x7 light blue */ + 0x852, /* 0x8 brown */ + 0xf60, /* 0x9 orange */ + 0xaaa, /* 0xa light gray */ + 0xf98, /* 0xb pink */ + 0x0d0, /* 0xc green */ + 0xff0, /* 0xd yellow */ + 0x0f9, /* 0xe aquamarine */ + 0xfff /* 0xf white */ +}; + +const word32 g_bw_hires_convert[4] = { + BIGEND(0x00000000), + BIGEND(0x0f0f0000), + BIGEND(0x00000f0f), + BIGEND(0x0f0f0f0f) +}; + +const word32 g_bw_dhires_convert[16] = { + BIGEND(0x00000000), + BIGEND(0x0f000000), + BIGEND(0x000f0000), + BIGEND(0x0f0f0000), + + BIGEND(0x00000f00), + BIGEND(0x0f000f00), + BIGEND(0x000f0f00), + BIGEND(0x0f0f0f00), + + BIGEND(0x0000000f), + BIGEND(0x0f00000f), + BIGEND(0x000f000f), + BIGEND(0x0f0f000f), + + BIGEND(0x00000f0f), + BIGEND(0x0f000f0f), + BIGEND(0x000f0f0f), + BIGEND(0x0f0f0f0f), +}; + +const word32 g_hires_convert[64] = { + BIGEND(0x00000000), /* 00,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 00,0001 = black, black, black, black */ + BIGEND(0x03030000), /* 00,0010 = purp , purp , black, black */ + BIGEND(0x0f0f0000), /* 00,0011 = white, white, black, black */ + BIGEND(0x00000c0c), /* 00,0100 = black, black, green, green */ + BIGEND(0x0c0c0c0c), /* 00,0101 = green, green, green, green */ + BIGEND(0x0f0f0f0f), /* 00,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 00,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 00,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 00,1001 = black, black, black, black */ + BIGEND(0x03030303), /* 00,1010 = purp , purp , purp , purp */ + BIGEND(0x0f0f0303), /* 00,1011 = white ,white, purp , purp */ + BIGEND(0x00000f0f), /* 00,1100 = black ,black, white, white */ + BIGEND(0x0c0c0f0f), /* 00,1101 = green ,green, white, white */ + BIGEND(0x0f0f0f0f), /* 00,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 00,1111 = white ,white, white, white */ + + BIGEND(0x00000000), /* 01,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 01,0001 = black, black, black, black */ + BIGEND(0x06060000), /* 01,0010 = blue , blue , black, black */ + BIGEND(0x0f0f0000), /* 01,0011 = white, white, black, black */ + BIGEND(0x00000c0c), /* 01,0100 = black, black, green, green */ + BIGEND(0x09090c0c), /* 01,0101 = orang, orang, green, green */ + BIGEND(0x0f0f0f0f), /* 01,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 01,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 01,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 01,1001 = black, black, black, black */ + BIGEND(0x06060303), /* 01,1010 = blue , blue , purp , purp */ + BIGEND(0x0f0f0303), /* 01,1011 = white ,white, purp , purp */ + BIGEND(0x00000f0f), /* 01,1100 = black ,black, white, white */ + BIGEND(0x09090f0f), /* 01,1101 = orang ,orang, white, white */ + BIGEND(0x0f0f0f0f), /* 01,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 01,1111 = white ,white, white, white */ + + BIGEND(0x00000000), /* 10,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 10,0001 = black, black, black, black */ + BIGEND(0x03030000), /* 10,0010 = purp , purp , black, black */ + BIGEND(0x0f0f0000), /* 10,0011 = white, white, black, black */ + BIGEND(0x00000909), /* 10,0100 = black, black, orang, orang */ + BIGEND(0x0c0c0909), /* 10,0101 = green, green, orang, orang */ + BIGEND(0x0f0f0f0f), /* 10,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 10,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 10,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 10,1001 = black, black, black, black */ + BIGEND(0x03030606), /* 10,1010 = purp , purp , blue , blue */ + BIGEND(0x0f0f0606), /* 10,1011 = white ,white, blue , blue */ + BIGEND(0x00000f0f), /* 10,1100 = black ,black, white, white */ + BIGEND(0x0c0c0f0f), /* 10,1101 = green ,green, white, white */ + BIGEND(0x0f0f0f0f), /* 10,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 10,1111 = white ,white, white, white */ + + BIGEND(0x00000000), /* 11,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 11,0001 = black, black, black, black */ + BIGEND(0x06060000), /* 11,0010 = blue , blue , black, black */ + BIGEND(0x0f0f0000), /* 11,0011 = white, white, black, black */ + BIGEND(0x00000909), /* 11,0100 = black, black, orang, orang */ + BIGEND(0x09090909), /* 11,0101 = orang, orang, orang, orang */ + BIGEND(0x0f0f0f0f), /* 11,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 11,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 11,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 11,1001 = black, black, black, black */ + BIGEND(0x06060606), /* 11,1010 = blue , blue , blue , blue */ + BIGEND(0x0f0f0606), /* 11,1011 = white ,white, blue , blue */ + BIGEND(0x00000f0f), /* 11,1100 = black ,black, white, white */ + BIGEND(0x09090f0f), /* 11,1101 = orang ,orang, white, white */ + BIGEND(0x0f0f0f0f), /* 11,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 11,1111 = white ,white, white, white */ +}; + +const int g_screen_index[] = { + 0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, + 0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8, + 0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0 +}; + + +void +video_init() +{ + word32 col[4]; + Kimage *kimage_ptr; + word32 *ptr; + word32 val0, val1, val2, val3; + word32 match_col; + word32 next_col, next2_col, next3_col; + word32 val; + word32 cur_col; + int width, height; + int total_bytes; + int i, j; +/* Initialize video system */ + + for(i = 0; i < 200; i++) { + g_a2_line_kimage[i] = (void *)0; + g_a2_line_stat[i] = -1; + g_a2_line_left_edge[i] = 0; + g_a2_line_right_edge[i] = 0; + } + for(i = 0; i < 200; i++) { + g_a2_new_all_stat[i] = 0; + g_a2_cur_all_stat[i] = 1; + for(j = 0; j < 8; j++) { + g_saved_line_palettes[i][j] = (word32)-1; + } + } + for(i = 0; i < 262; i++) { + g_cur_border_colors[i] = -1; + } + + g_new_a2_stat_cur_line = 0; + + dev_video_init(); + + read_a2_font(); + + vid_printf("Zeroing out video memory\n"); + + for(i = 0; i < 7; i++) { + switch(i) { + case 0: + kimage_ptr = &(g_kimage_text[0]); + break; + case 1: + kimage_ptr = &(g_kimage_text[1]); + break; + case 2: + kimage_ptr = &(g_kimage_hires[0]); + break; + case 3: + kimage_ptr = &(g_kimage_hires[1]); + break; + case 4: + kimage_ptr = &g_kimage_superhires; + break; + case 5: + kimage_ptr = &g_kimage_border_sides; + break; + case 6: + kimage_ptr = &g_kimage_border_special; + break; + default: + printf("i: %d, unknown\n", i); + exit(3); + } + + ptr = (word32 *)kimage_ptr->data_ptr; + width = kimage_ptr->width_act; + height = kimage_ptr->height; + total_bytes = (kimage_ptr->mdepth >> 3) * width * height; + + for(j = 0; j < total_bytes >> 2; j++) { + *ptr++ = 0; + } + } + + for(i = 0; i < SLOW_MEM_CH_SIZE; i++) { + slow_mem_changed[i] = (word32)-1; + } + + /* create g_expanded_col_* */ + for(i = 0; i < 16; i++) { + val = (g_lores_colors[i] >> 0) & 0xf; + g_expanded_col_0[i] = val; + + val = (g_lores_colors[i] >> 4) & 0xf; + g_expanded_col_1[i] = val; + + val = (g_lores_colors[i] >> 8) & 0xf; + g_expanded_col_2[i] = val; + } + + /* create g_dhires_convert[] array */ + for(i = 0; i < 4096; i++) { + /* Convert index bits 11:0 where 3:0 is the previous color */ + /* and 7:4 is the current color to translate */ + /* Bit 4 will be the first pixel displayed on the screen */ + match_col = i & 0xf; + for(j = 0; j < 4; j++) { + cur_col = (i >> (1 + j)) & 0xf; + next_col = (i >> (2 + j)) & 0xf; + next2_col = (i >> (3 + j)) & 0xf; + next3_col = (i >> (4 + j)) & 0xf; + cur_col = (((cur_col << 4) + cur_col) >> (3 - j)) & 0xf; + + if((cur_col == 0xf) || (next_col == 0xf) || + (next2_col == 0xf) || + (next3_col == 0xf)) { + cur_col = 0xf; + col[j] = cur_col; + match_col = cur_col; + } else if((cur_col == 0) || (next_col == 0) || + (next2_col == 0) || (next3_col == 0)) { + cur_col = 0; + col[j] = cur_col; + match_col = cur_col; + } else { + col[j] = cur_col; + match_col = cur_col; + } + } + if(g_use_dhr140) { + for(j = 0; j < 4; j++) { + col[j] = (i >> 4) & 0xf; + } + } + val0 = g_dhires_colors_16[col[0] & 0xf]; + val1 = g_dhires_colors_16[col[1] & 0xf]; + val2 = g_dhires_colors_16[col[2] & 0xf]; + val3 = g_dhires_colors_16[col[3] & 0xf]; +#ifdef KEGS_LITTLE_ENDIAN + val = (val3 << 24) + (val2 << 16) + (val1 << 8) + val0; +#else + val = (val0 << 24) + (val1 << 16) + (val2 << 8) + val3; +#endif + g_dhires_convert[i] = val; + } + + change_display_mode(g_cur_dcycs); + video_reset(); + display_screen(); + + vid_printf("Done with display_screen\n"); + + fflush(stdout); +} + +void +show_a2_line_stuff() +{ + int i; + + for(i = 0; i < 200; i++) { + printf("line: %d: stat: %04x, ptr: %p, " + "left_edge:%d, right_edge:%d\n", + i, g_a2_line_stat[i], g_a2_line_kimage[i], + g_a2_line_left_edge[i], + g_a2_line_right_edge[i]); + } + + printf("new_a2_stat_cur_line: %d\n", g_new_a2_stat_cur_line); + for(i = 0; i < 200; i++) { + printf("cur_all[%d]: %03x new_all: %03x\n", i, + g_a2_cur_all_stat[i], g_a2_new_all_stat[i]); + } + +} + +int g_flash_count = 0; + +void +video_reset() +{ + int i; + + g_installed_full_superhires_colormap = (g_screen_depth != 8); + g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR); + if(g_use_bw_hires) { + g_cur_a2_stat |= ALL_STAT_COLOR_C021; + } + + g_palette_change_summary = 0; + for(i = 0; i < 16; i++) { + g_palette_change_cnt[i] = 0; + } + + /* install_a2vid_colormap(); */ + video_update_colormap(); +} + +int g_screen_redraw_skip_count = 0; +int g_screen_redraw_skip_amt = -1; + +word32 g_cycs_in_check_input = 0; + +void +video_update() +{ + register word32 start_time; + register word32 end_time; + int did_video; + + update_border_info(); + + GET_ITIMER(start_time); + check_input_events(); + GET_ITIMER(end_time); + + g_cycs_in_check_input += (end_time - start_time); + + g_screen_redraw_skip_count--; + did_video = 0; + if(g_screen_redraw_skip_count < 0) { + did_video = 1; + video_update_event_line(262); + g_screen_redraw_skip_count = g_screen_redraw_skip_amt; + } + + /* update flash */ + g_flash_count++; + if(g_flash_count >= 30) { + g_flash_count = 0; + g_cur_a2_stat ^= ALL_STAT_FLASH_STATE; + change_display_mode(g_cur_dcycs); + } + + + check_a2vid_palette(); + + + if(did_video) { + g_new_a2_stat_cur_line = 0; + g_a2_new_all_stat[0] = (g_cur_a2_stat & (~ALL_STAT_PAGE2)) + + PAGE2; + g_vid_update_last_line = 0; + video_update_through_line(0); + } +} + + +int +video_all_stat_to_line_stat(int line, int new_all_stat) +{ + int page, color, dbl; + int st80, hires, annunc3, mix_t_gr; + int altchar, text_color, bg_color, flash_state; + int mode; + + st80 = new_all_stat & ALL_STAT_ST80; + hires = new_all_stat & ALL_STAT_HIRES; + annunc3 = new_all_stat & ALL_STAT_ANNUNC3; + mix_t_gr = new_all_stat & ALL_STAT_MIX_T_GR; + + page = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_PAGE2, 1) && !st80; + color = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_COLOR_C021, 1); + dbl = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_VID80, 1); + + altchar = 0; text_color = 0; bg_color = 0; flash_state = 0; + + if(new_all_stat & ALL_STAT_SUPER_HIRES) { + mode = MODE_SUPER_HIRES; + page = 0; dbl = 0; color = 0; + } else { + if(line >= 192) { + mode = MODE_BORDER; + page = 0; dbl = 0; color = 0; + } else if((new_all_stat & ALL_STAT_TEXT) || + (line >= 160 && mix_t_gr)) { + mode = MODE_TEXT; + color = 0; + altchar = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_ALTCHARSET, 1); + text_color = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_TEXT_COLOR, 4); + bg_color = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_BG_COLOR, 4); + flash_state = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_FLASH_STATE, 1); + if(altchar) { + /* don't bother flashing if altchar on */ + flash_state = 0; + } + } else { + /* obey the graphics mode */ + dbl = dbl && !annunc3; + if(hires) { + color = color | EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_DIS_COLOR_DHIRES, 1); + mode = MODE_HGR; + } else { + mode = MODE_GR; + } + } + } + + return((text_color << 12) + (bg_color << 8) + (altchar << 7) + + (mode << 4) + (flash_state << 3) + (page << 2) + + (color << 1) + dbl); +} + +int * +video_update_kimage_ptr(int line, int new_stat) +{ + Kimage *kimage_ptr; + int *mode_ptr; + int page; + int mode; + + page = (new_stat >> 2) & 1; + mode = (new_stat >> 4) & 7; + + switch(mode) { + case MODE_TEXT: + case MODE_GR: + kimage_ptr = &(g_kimage_text[page]); + mode_ptr = &(g_mode_text[page][0]); + break; + case MODE_HGR: + kimage_ptr = &(g_kimage_hires[page]); + mode_ptr = &(g_mode_hires[page][0]); + /* arrange to force superhires reparse since we use the */ + /* same memory */ + g_mode_superhires[line] = -1; + break; + case MODE_SUPER_HIRES: + kimage_ptr = &g_kimage_superhires; + mode_ptr = &(g_mode_superhires[0]); + /* arrange to force hires reparse since we use the */ + /* same memory */ + g_mode_hires[0][line] = -1; + g_mode_hires[1][line] = -1; + break; + case MODE_BORDER: + /* Hack: reuse text page last line as the special border */ + kimage_ptr = &(g_kimage_text[0]); + mode_ptr = &(g_mode_border[0]); + break; + default: + halt_printf("update_a2_ptrs: mode: %d unknown!\n", mode); + return &(g_mode_superhires[0]); + } + + g_a2_line_kimage[line] = kimage_ptr; + return mode_ptr; +} + +void +change_a2vid_palette(int new_palette) +{ + int i; + + for(i = 0; i < 200; i++) { + g_mode_text[0][i] = -1; + g_mode_text[1][i] = -1; + g_mode_hires[0][i] = -1; + g_mode_hires[1][i] = -1; + g_mode_superhires[i] = -1; + g_mode_border[i] = -1; + } + + printf("Changed a2vid_palette to %x\n", new_palette); + + g_a2vid_palette = new_palette; + g_cur_a2_stat = (g_cur_a2_stat & (~ALL_STAT_A2VID_PALETTE)) + + (new_palette << BIT_ALL_STAT_A2VID_PALETTE); + change_display_mode(g_cur_dcycs); + + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_status_refresh_needed = 1; + g_palette_change_cnt[new_palette]++; + g_border_last_vbl_changes = 1; + for(i = 0; i < 262; i++) { + g_cur_border_colors[i] = -1; + } +} + +int g_num_a2vid_palette_checks = 1; +int g_shr_palette_used[16]; + +void +check_a2vid_palette() +{ + int sum; + int min; + int val; + int min_pos; + int count_cur; + int i; + + /* determine if g_a2vid_palette should change */ + /* This is the palette of least use on superhires so that the */ + /* borders don't change when all 256 superhires colors are used */ + + g_num_a2vid_palette_checks--; + if(g_num_a2vid_palette_checks || g_installed_full_superhires_colormap){ + return; + } + + g_num_a2vid_palette_checks = 60; + + sum = 0; + min = 0x100000; + min_pos = -1; + count_cur = g_shr_palette_used[g_a2vid_palette]; + + for(i = 0; i < 16; i++) { + val = g_shr_palette_used[i]; + g_shr_palette_used[i] = 0; + if(val < min) { + min = val; + min_pos = i; + } + sum += val; + } + + if(g_a2vid_palette != min_pos && (count_cur > min)) { + change_a2vid_palette(min_pos); + } +} + +void +change_display_mode(double dcycs) +{ + int line, tmp_line; + + line = ((get_lines_since_vbl(dcycs) + 0xff) >> 8); + if(line < 0) { + line = 0; + halt_printf("Line < 0!\n"); + } + tmp_line = MIN(199, line); + + video_update_all_stat_through_line(tmp_line); + + if(line < 200) { + g_a2_new_all_stat[line] = + (g_cur_a2_stat & (~ALL_STAT_PAGE2)) + PAGE2; + } + /* otherwise, g_cur_a2_stat is covered at the end of vbl */ +} + +void +video_update_all_stat_through_line(int line) +{ + int start_line; + int prev_stat; + int max_line; + int i; + + start_line = g_new_a2_stat_cur_line; + prev_stat = g_a2_new_all_stat[start_line]; + + max_line = MIN(199, line); + + for(i = start_line + 1; i <= max_line; i++) { + g_a2_new_all_stat[i] = prev_stat; + } + g_new_a2_stat_cur_line = max_line; +} + + +#define MAX_BORDER_CHANGES 16384 + +STRUCT(Border_changes) { + float fcycs; + int val; +}; + +Border_changes g_border_changes[MAX_BORDER_CHANGES]; +int g_num_border_changes = 0; + +void +change_border_color(double dcycs, int val) +{ + int pos; + + pos = g_num_border_changes; + g_border_changes[pos].fcycs = dcycs - g_last_vbl_dcycs; + g_border_changes[pos].val = val; + + pos++; + g_num_border_changes = pos; + + if(pos >= MAX_BORDER_CHANGES) { + halt_printf("num border changes: %d\n", pos); + g_num_border_changes = 0; + } +} + +void +update_border_info() +{ + double dlines_per_dcyc; + double dcycs, dline, dcyc_line_start; + int offset; + int new_line_offset, last_line_offset; + int new_line; + int new_val; + int limit; + int color_now; + int i; + + /* to get this routine to redraw the border, change */ + /* g_vbl_border_color, set g_border_last_vbl_changes = 1 */ + /* and change the cur_border_colors[] array */ + + color_now = g_vbl_border_color; + + dlines_per_dcyc = (double)(262.0 / DCYCS_IN_16MS); + limit = g_num_border_changes; + if(g_border_last_vbl_changes || limit) { + /* add a dummy entry */ + g_border_changes[limit].fcycs = DCYCS_IN_16MS + 21.0; + g_border_changes[limit].val = g_border_color; + limit++; + } + last_line_offset = (-1 << 8) + 44; + for(i = 0; i < limit; i++) { + dcycs = g_border_changes[i].fcycs; + dline = dcycs * dlines_per_dcyc; + new_line = (int)dline; + dcyc_line_start = (double)new_line * (DCYCS_IN_16MS/262.0); + offset = ((int)(dcycs - dcyc_line_start)) & 0xff; + + /* here comes the tricky part */ + /* offset is from 0 to 65, where 0-3 is the right border of */ + /* the previous line, 4-20 is horiz blanking, 21-24 is the */ + /* left border and 25-64 is the main window */ + /* Convert this to a new notation which is 0-3 is the left */ + /* border, 4-43 is the main window, and 44-47 is the right */ + /* basically, add -21 to offset, and wrap < 0 to previous ln */ + /* note this makes line -1 offset 44-47 the left hand border */ + /* for true line 261 on the screen */ + offset -= 21; + if(offset < 0) { + new_line--; + offset += 64; + } + new_val = g_border_changes[i].val; + new_line_offset = (new_line << 8) + offset; + + if(new_line_offset < -256 || new_line_offset >(262*256 + 0x80)){ + printf("new_line_offset: %05x\n", new_line_offset); + new_line_offset = last_line_offset; + } + while(last_line_offset < new_line_offset) { + /* see if this will finish it */ + if((last_line_offset & -256)==(new_line_offset & -256)){ + update_border_line(last_line_offset, + new_line_offset, color_now); + last_line_offset = new_line_offset; + } else { + update_border_line(last_line_offset, + (last_line_offset & -256) + 65, + color_now); + last_line_offset =(last_line_offset & -256)+256; + } + } + + color_now = new_val; + } + +#if 0 + if(g_num_border_changes) { + printf("Border changes: %d\n", g_num_border_changes); + } +#endif + + if(limit > 1) { + g_border_last_vbl_changes = 1; + } else { + g_border_last_vbl_changes = 0; + } + + g_num_border_changes = 0; + g_vbl_border_color = g_border_color; +} + +void +update_border_line(int st_line_offset, int end_line_offset, int color) +{ + word32 val; + int st_offset, end_offset; + int left, right; + int line; + + line = st_line_offset >> 8; + if(line != (end_line_offset >> 8)) { + halt_printf("ubl, %04x %04x %02x!\n", st_line_offset, + end_line_offset, color); + } + if(line < -1 || line >= 262) { + halt_printf("ubl-b, mod line is %d\n", line); + line = 0; + } + if(line < 0 || line >= 262) { + line = 0; + } + + st_offset = st_line_offset & 0xff; + end_offset = end_line_offset & 0xff; + + if((st_offset == 0) && (end_offset >= 0x41)) { + /* might be the same as last time, save some work */ + if(g_cur_border_colors[line] == color) { + return; + } + g_cur_border_colors[line] = color; + } else { + g_cur_border_colors[line] = -1; + } + + val = (color + (g_a2vid_palette << 4)); + val = (val << 24) + (val << 16) + (val << 8) + val; + + /* 0-3: left border, 4-43: main window, 44-47: right border */ + /* 48-65: horiz blanking */ + /* first, do the sides from line 0 to line 199 */ + if((line < 200) || (line >= 262)) { + if(line >= 262) { + line = 0; + } + if(st_offset < 4) { + /* left side */ + left = st_offset; + right = MIN(4, end_offset); + video_border_pixel_write(&g_kimage_border_sides, + 2*line, 2, val, (left * BORDER_WIDTH)/4, + (right * BORDER_WIDTH) / 4); + + g_border_sides_refresh_needed = 1; + } + if((st_offset < 48) && (end_offset >= 44)) { + /* right side */ + left = MAX(0, st_offset - 44); + right = MIN(4, end_offset - 44); + video_border_pixel_write(&g_kimage_border_sides, + 2*line, 2, val, + 32 + (left * EFF_BORDER_WIDTH/4), + 32 + (right * EFF_BORDER_WIDTH/4)); + g_border_sides_refresh_needed = 1; + } + } + + if((line >= 192) && (line < 200)) { + if(st_offset < 44 && end_offset > 4) { + left = MAX(0, st_offset - 4); + right = MIN(40, end_offset - 4); + video_border_pixel_write(&g_kimage_text[0], + 2*line, 2, val, left * 640 / 40, + right * 640 / 40); + g_border_line24_refresh_needed = 1; + } + } + + /* now do the bottom, lines 200 to 215 */ + if((line >= 200) && (line < (200 + BASE_MARGIN_BOTTOM/2)) ) { + line -= 200; + left = st_offset; + right = MIN(48, end_offset); + video_border_pixel_write(&g_kimage_border_special, 2*line, 2, + val, (left * X_A2_WINDOW_WIDTH / 48), + (right * X_A2_WINDOW_WIDTH / 48)); + g_border_special_refresh_needed = 1; + } + + /* and top, lines 236 to 262 */ + if((line >= (262 - BASE_MARGIN_TOP/2)) && (line < 262)) { + line -= (262 - BASE_MARGIN_TOP/2); + left = st_offset; + right = MIN(48, end_offset); + video_border_pixel_write(&g_kimage_border_special, + BASE_MARGIN_BOTTOM + 2*line, 2, val, + (left * X_A2_WINDOW_WIDTH / 48), + (right * X_A2_WINDOW_WIDTH / 48)); + g_border_special_refresh_needed = 1; + } +} + +void +video_border_pixel_write(Kimage *kimage_ptr, int starty, int num_lines, + word32 val, int st_off, int end_off) +{ + word32 *ptr; + int width; + int width_act; + int mdepth; + int num_words, num_bytes; + int bytes_per_pix; + int i, j; + + if(end_off <= st_off) { + return; + } + + width = end_off - st_off; + width_act = kimage_ptr->width_act; + mdepth = kimage_ptr->mdepth; + bytes_per_pix = mdepth >> 3; + num_bytes = width * bytes_per_pix; + num_words = num_bytes >> 2; + + if(width > width_act) { + halt_printf("border write but width %d > act %d\n", width, + width_act); + } + + if(mdepth == 16) { + val = g_a2palette_8to1624[val & 0xff]; + val = (val << 16) + val; + } else if(mdepth == 32) { + /* 32-bit pixels */ + val = g_a2palette_8to1624[val & 0xff]; + } + + for(i = 0; i < num_lines; i++) { + ptr = (word32 *)&(kimage_ptr->data_ptr[ + (starty + i)*width_act*bytes_per_pix]); + ptr += ((st_off * bytes_per_pix) / 4); + /* HACK: the above isn't really right when bytes_per_pix is */ + /* less than four... */ + for(j = 0; j < num_words; j++) { + *ptr++ = val; + } + } +} + + +#define CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, do_clear) \ + ch_ptr = &(slow_mem_changed[mem_ptr >> CHANGE_SHIFT]); \ + ch_bitpos = 0; \ + bits_per_line = 40 >> SHIFT_PER_CHANGE; \ + ch_shift_amount = (mem_ptr >> SHIFT_PER_CHANGE) & 0x1f; \ + mask_per_line = (-(1 << (32 - bits_per_line))); \ + mask_per_line = mask_per_line >> ch_shift_amount; \ + ch_mask = *ch_ptr & mask_per_line; \ + if(do_clear) { \ + *ch_ptr = *ch_ptr & (~ch_mask); \ + } \ + ch_mask = ch_mask << ch_shift_amount; \ + \ + if(reparse) { \ + ch_mask = - (1 << (32 - bits_per_line)); \ + } + +#define CH_LOOP_A2_VID(ch_mask, ch_tmp) \ + ch_tmp = ch_mask & 0x80000000; \ + ch_mask = ch_mask << 1; \ + \ + if(!ch_tmp) { \ + continue; \ + } + +void +redraw_changed_text_40(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, + int pixels_per_line) +{ + register word32 start_time, end_time; + word32 *img_ptr, *img_ptr2; + word32 *save_img_ptr, *save_img_ptr2; + word32 *ch_ptr; + const word32 *font_ptr1; + const word32 *font_ptr2; + byte *slow_mem_ptr; + byte *b_ptr; + word32 ch_mask; + word32 ch_tmp; + word32 line_mask; + word32 mask_per_line; + word32 mem_ptr; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 palette_add; + word32 diff_val; + word32 and_val; + word32 add_val; + word32 ff_val; + word32 val0, val1; + int flash_state; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line_mod8, st_line; + int i; + + /* always redraws to the next multiple of 8 lines due to redraw */ + /* issues: char changed on one screen redraw at line 0 with */ + /* num_lines=1. We need to have drawn lines 1-7 also since line 1 */ + /* will not see any changed bytes */ + st_line_mod8 = start_line & 7; + st_line = start_line; + + start_line = start_line >> 3; + + y = start_line; + line_mask = 1 << (y); + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr); + } + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + /* avoid clearing changed bits unless we are line 0 (mod 8) */ + + if(ch_mask == 0) { + return; + } + + GET_ITIMER(start_time); + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + diff_val = (fg_val - bg_val) & 0xf; + and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24); + add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24); + ff_val = 0x0f0f0f0f; + + + flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE); + + for(x1 = 0; x1 < 40; x1 += shift_per) { + + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(8*y + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = *slow_mem_ptr++; + val1 = *slow_mem_ptr++; + + if(!altcharset) { + if(val0 >= 0x40 && val0 < 0x80) { + if(flash_state) { + val0 += 0x40; + } else { + val0 -= 0x40; + } + } + if(val1 >= 0x40 && val1 < 0x80) { + if(flash_state) { + val1 += 0x40; + } else { + val1 -= 0x40; + } + } + } + save_img_ptr = img_ptr; + save_img_ptr2 = img_ptr2; + + for(i = st_line_mod8; i < 8; i++) { + font_ptr1 = &(g_font40_even_bits[val0][i][0]); + tmp0 = (font_ptr1[0] & and_val) + add_val; + tmp1 = (font_ptr1[1] & and_val) + add_val; + tmp2 = (font_ptr1[2] & and_val) + add_val; + + font_ptr2 = &(g_font40_odd_bits[val1][i][0]); + tmp3 = ((font_ptr1[3]+font_ptr2[0]) & and_val)+ + add_val; + + tmp4 = (font_ptr2[1] & and_val) + add_val; + tmp5 = (font_ptr2[2] & and_val) + add_val; + tmp6 = (font_ptr2[3] & and_val) + add_val; + + tmp0 = (tmp0 & ff_val) + palette_add; + tmp1 = (tmp1 & ff_val) + palette_add; + tmp2 = (tmp2 & ff_val) + palette_add; + tmp3 = (tmp3 & ff_val) + palette_add; + tmp4 = (tmp4 & ff_val) + palette_add; + tmp5 = (tmp5 & ff_val) + palette_add; + tmp6 = (tmp6 & ff_val) + palette_add; + + img_ptr[0] = tmp0; + img_ptr[1] = tmp1; + img_ptr[2] = tmp2; + img_ptr[3] = tmp3; + img_ptr[4] = tmp4; + img_ptr[5] = tmp5; + img_ptr[6] = tmp6; + + img_ptr2[0] = tmp0; + img_ptr2[1] = tmp1; + img_ptr2[2] = tmp2; + img_ptr2[3] = tmp3; + img_ptr2[4] = tmp4; + img_ptr2[5] = tmp5; + img_ptr2[6] = tmp6; + + img_ptr += (2*pixels_per_line)/4; + img_ptr2 += (2*pixels_per_line)/4; + } + + img_ptr = save_img_ptr + 7; + img_ptr2 = save_img_ptr2 + 7; + } + } + GET_ITIMER(end_time); + + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + if(left >= right || left < 0 || right < 0) { + printf("line %d, 40: left >= right: %d >= %d\n", + start_line, left, right); + } + + g_cycs_in_40col += (end_time - start_time); + + g_need_redraw = 0; +} + +void +redraw_changed_text_80(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, + int pixels_per_line) +{ + const word32 *font_ptr0, *font_ptr1, *font_ptr2, *font_ptr3; + word32 *ch_ptr; + word32 *img_ptr, *img_ptr2; + word32 *save_img_ptr, *save_img_ptr2; + byte *b_ptr; + byte *slow_mem_ptr; + word32 ch_mask; + word32 ch_tmp; + word32 mask_per_line; + word32 mem_ptr; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 diff_val; + word32 add_val, and_val, ff_val; + word32 palette_add; + word32 line_mask; + word32 val0, val1, val2, val3; + int st_line_mod8, st_line; + int flash_state; + int y; + int x1, x2; + int i; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + + st_line_mod8 = start_line & 7; + st_line = start_line; + + start_line = start_line >> 3; + + y = start_line; + line_mask = 1 << (y); + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr); + } + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + + if(ch_mask == 0) { + return; + } + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + diff_val = (fg_val - bg_val) & 0xf; + add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24); + and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24); + ff_val = 0x0f0f0f0f; + + flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE); + + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + + for(x2 = 0; x2 < shift_per; x2 += 2) { + /* do 4 chars at once! */ + + val1 = slow_mem_ptr[0]; + val3 = slow_mem_ptr[1]; + val0 = slow_mem_ptr[0x10000]; + val2 = slow_mem_ptr[0x10001]; + slow_mem_ptr += 2; + + if(!altcharset) { + if(val0 >= 0x40 && val0 < 0x80) { + if(flash_state) { + val0 += 0x40; + } else { + val0 -= 0x40; + } + } + if(val1 >= 0x40 && val1 < 0x80) { + if(flash_state) { + val1 += 0x40; + } else { + val1 -= 0x40; + } + } + if(val2 >= 0x40 && val2 < 0x80) { + if(flash_state) { + val2 += 0x40; + } else { + val2 -= 0x40; + } + } + if(val3 >= 0x40 && val3 < 0x80) { + if(flash_state) { + val3 += 0x40; + } else { + val3 -= 0x40; + } + } + } + save_img_ptr = img_ptr; + save_img_ptr2 = img_ptr2; + + for(i = st_line_mod8; i < 8; i++) { + font_ptr0 = &(g_font80_off0_bits[val0][i][0]); + tmp0 = (font_ptr0[0] & and_val) + add_val; + + font_ptr3 = &(g_font80_off3_bits[val1][i][0]); + tmp1 = ((font_ptr0[1]+font_ptr3[0]) & and_val)+ + add_val; + /* 3 bytes from ptr0, 1 from ptr3 */ + tmp2 = (font_ptr3[1] & and_val) + add_val; + + font_ptr2 = &(g_font80_off2_bits[val2][i][0]); + tmp3 = ((font_ptr3[2]+font_ptr2[0]) & and_val)+ + add_val; + /* 2 bytes from ptr3, 2 from ptr2*/ + tmp4 = (font_ptr2[1] & and_val) + add_val; + + font_ptr1 = &(g_font80_off1_bits[val3][i][0]); + tmp5 = ((font_ptr2[2]+font_ptr1[0]) & and_val)+ + add_val; + /* 1 byte from ptr2, 3 from ptr1 */ + tmp6 = (font_ptr1[1] & and_val) + add_val; + + tmp0 = (tmp0 & ff_val) + palette_add; + tmp1 = (tmp1 & ff_val) + palette_add; + tmp2 = (tmp2 & ff_val) + palette_add; + tmp3 = (tmp3 & ff_val) + palette_add; + tmp4 = (tmp4 & ff_val) + palette_add; + tmp5 = (tmp5 & ff_val) + palette_add; + tmp6 = (tmp6 & ff_val) + palette_add; + + img_ptr[0] = tmp0; + img_ptr[1] = tmp1; + img_ptr[2] = tmp2; + img_ptr[3] = tmp3; + img_ptr[4] = tmp4; + img_ptr[5] = tmp5; + img_ptr[6] = tmp6; + + img_ptr2[0] = tmp0; + img_ptr2[1] = tmp1; + img_ptr2[2] = tmp2; + img_ptr2[3] = tmp3; + img_ptr2[4] = tmp4; + img_ptr2[5] = tmp5; + img_ptr2[6] = tmp6; + + img_ptr += (2*pixels_per_line)/4; + img_ptr2 += (2*pixels_per_line)/4; + } + + img_ptr = save_img_ptr + 7; + img_ptr2 = save_img_ptr2 + 7; + + } + } + + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + if(left >= right || left < 0 || right < 0) { + printf("line %d, 80: left >= right: %d >= %d\n", + start_line, left, right); + } + + g_need_redraw = 0; +} + +void +redraw_changed_gr(int start_offset, int start_line, int num_lines, int reparse, + byte *screen_data, int pixels_per_line) +{ + word32 *img_ptr; + word32 *save_img_ptr; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 line_mask; + word32 val0, val1; + word32 val0_wd, val1_wd; + word32 val01_wd; + word32 val_even, val_odd; + word32 palette_add; + int half; + int x1, x2; + int y; + int y2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line_mod8, st_line, eff_line, end_line; + int i; + + st_line_mod8 = start_line & 7; + st_line = start_line; + end_line = 8; // st_line_mod8 + num_lines; + + start_line = start_line >> 3; + + y = start_line; + line_mask = 1 << y; + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + printf("redraw_changed_gr: mem_ptr: %08x\n", mem_ptr); + } + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + + if(ch_mask == 0) { + return; + } + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val_even = *slow_mem_ptr++; + val_odd = *slow_mem_ptr++; + + save_img_ptr = img_ptr; + + for(half = 0; half < 2; half++) { + val0 = val_even & 0xf; + val1 = val_odd & 0xf; + val0_wd = (val0 << 24) + (val0 << 16) + + (val0 << 8) + val0; + val1_wd = (val1 << 24) + (val1 << 16) + + (val1 << 8) + val1; +#ifdef KEGS_LITTLE_ENDIAN + val01_wd = (val1_wd << 16) + (val0_wd & 0xffff); +#else + val01_wd = (val0_wd << 16) + (val1_wd & 0xffff); +#endif + + for(y2 = 0; y2 < 8; y2++) { + eff_line = half*4 + (y2 >> 1); + if((eff_line < st_line_mod8) || + (eff_line > end_line)) { + continue; + } + + img_ptr[0] = val0_wd + palette_add; + img_ptr[1] = val0_wd + palette_add; + img_ptr[2] = val0_wd + palette_add; + img_ptr[3] = val01_wd + palette_add; + img_ptr[4] = val1_wd + palette_add; + img_ptr[5] = val1_wd + palette_add; + img_ptr[6] = val1_wd + palette_add; + img_ptr += (pixels_per_line)/4; + } + + + val_even = val_even >> 4; + val_odd = val_odd >> 4; + } + + img_ptr = save_img_ptr + 7; + } + } + + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + g_need_redraw = 0; +} + +void +redraw_changed_dbl_gr(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) +{ + word32 *img_ptr; + word32 *save_img_ptr; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 line_mask; + word32 val0, val1, val2, val3; + word32 val0_wd, val1_wd, val2_wd, val3_wd; + word32 val01_wd, val12_wd, val23_wd; + word32 val_even_main, val_odd_main; + word32 val_even_aux, val_odd_aux; + word32 palette_add; + int half; + int x1, x2; + int y; + int y2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line_mod8, st_line, eff_line, end_line; + int i; + + st_line_mod8 = start_line & 7; + end_line = 8; // st_line_mod8 + num_lines + st_line = start_line; + + start_line = start_line >> 3; + + y = start_line; + line_mask = 1 << y; + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + printf("redraw_changed_dbl_gr: mem_ptr: %08x\n", mem_ptr); + } + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + + if(ch_mask == 0) { + return; + } + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val_even_main = slow_mem_ptr[0]; + val_odd_main = slow_mem_ptr[1]; + val_even_aux = slow_mem_ptr[0x10000]; + val_odd_aux = slow_mem_ptr[0x10001]; + slow_mem_ptr += 2; + + save_img_ptr = img_ptr; + + for(half = 0; half < 2; half++) { + val0 = val_even_aux & 0xf; + val1 = val_even_main & 0xf; + val2 = val_odd_aux & 0xf; + val3 = val_odd_main & 0xf; + + /* Handle funny pattern of dbl gr aux mem */ + val0 = ((val0 << 1) & 0xf) + (val0 >> 3); + val2 = ((val2 << 1) & 0xf) + (val2 >> 3); + + val0_wd = (val0 << 24) + (val0 << 16) + + (val0 << 8) + val0; + val1_wd = (val1 << 24) + (val1 << 16) + + (val1 << 8) + val1; + val2_wd = (val2 << 24) + (val2 << 16) + + (val2 << 8) + val2; + val3_wd = (val3 << 24) + (val3 << 16) + + (val3 << 8) + val3; +#ifdef KEGS_LITTLE_ENDIAN + val01_wd = (val1_wd << 24) + (val0_wd&0xffffff); + val12_wd = (val2_wd << 16) + (val1_wd & 0xffff); + val23_wd = (val3_wd << 8) + (val2_wd & 0xff); +#else + val01_wd = (val0_wd << 8) + (val1_wd & 0xff); + val12_wd = (val1_wd << 16) + (val2_wd & 0xffff); + val23_wd = (val2_wd << 24) + (val3_wd&0xffffff); +#endif + + for(y2 = 0; y2 < 8; y2++) { + eff_line = half*4 + (y2 >> 1); + if((eff_line < st_line_mod8) || + (eff_line > end_line)) { + continue; + } + img_ptr[0] = val0_wd + palette_add; + img_ptr[1] = val01_wd + palette_add; + img_ptr[2] = val1_wd + palette_add; + img_ptr[3] = val12_wd + palette_add; + img_ptr[4] = val2_wd + palette_add; + img_ptr[5] = val23_wd + palette_add; + img_ptr[6] = val3_wd + palette_add; + img_ptr += (pixels_per_line)/4; + } + + val_even_aux = val_even_aux >> 4; + val_even_main = val_even_main >> 4; + val_odd_aux = val_odd_aux >> 4; + val_odd_main = val_odd_main >> 4; + } + + img_ptr = save_img_ptr + 7; + } + } + + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + g_need_redraw = 0; +} + +void +redraw_changed_hires(int start_offset, int start_line, int num_lines, + int color, int reparse, byte *screen_data, int pixels_per_line) +{ + if(!color) { + redraw_changed_hires_color(start_offset, start_line, num_lines, + reparse, screen_data, pixels_per_line); + } else { + redraw_changed_hires_bw(start_offset, start_line, num_lines, + reparse, screen_data, pixels_per_line); + } +} + +void +redraw_changed_hires_bw(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) +{ + word32 *img_ptr, *img_ptr2; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 mem_ptr; + word32 val0, val1; + word32 val_whole; + word32 line_mask; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i; + + st_line = start_line; + start_line = start_line >> 3; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + + g_screen_index[y >> 3]) + start_offset; + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + + if(ch_mask == 0) { + continue; + } + + /* Hires depends on adjacent bits, so also reparse adjacent */ + /* regions so that if bits on the edge change, redrawing is */ + /* correct */ + ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = *slow_mem_ptr++; + val1 = *slow_mem_ptr++; + + val_whole = ((val1 & 0x7f) << 7) +(val0 & 0x7f); + + tmp0 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp1 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp2 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp3 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp4 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp5 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp6 = g_bw_hires_convert[val_whole & 3]; + + img_ptr[0] = tmp0 + palette_add; + img_ptr[1] = tmp1 + palette_add; + img_ptr[2] = tmp2 + palette_add; + img_ptr[3] = tmp3 + palette_add; + img_ptr[4] = tmp4 + palette_add; + img_ptr[5] = tmp5 + palette_add; + img_ptr[6] = tmp6 + palette_add; + + img_ptr2[0] = tmp0 + palette_add; + img_ptr2[1] = tmp1 + palette_add; + img_ptr2[2] = tmp2 + palette_add; + img_ptr2[3] = tmp3 + palette_add; + img_ptr2[4] = tmp4 + palette_add; + img_ptr2[5] = tmp5 + palette_add; + img_ptr2[6] = tmp6 + palette_add; + + img_ptr += 7; + img_ptr2 += 7; + } + } + } + + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + g_need_redraw = 0; +} + +void +redraw_changed_hires_color(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) +{ + word32 *img_ptr, *img_ptr2; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 val0, val1; + word32 val_whole; + word32 pix_val; + word32 line_mask; + word32 prev_pixel; + word32 prev_hi; + word32 loc_hi; + word32 val_hi; + word32 tmp_val; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i, j; + + st_line = start_line; + + start_line = start_line >> 3; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + + g_screen_index[y >> 3]) + start_offset; + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + + if(ch_mask == 0) { + continue; + } + + /* Hires depends on adjacent bits, so also reparse adjacent */ + /* regions so that if bits on the edge change, redrawing is */ + /* correct */ + ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + for(x1 = 0; x1 < 40; x1 += shift_per) { + + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + + prev_pixel = 0; + prev_hi = 0; + + if(x1 > 0) { + tmp_val = slow_mem_ptr[-1]; + prev_pixel = (tmp_val >> 6) & 1; + prev_hi = (tmp_val >> 7) & 0x1; + } + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = *slow_mem_ptr++; + val1 = *slow_mem_ptr++; + + val_whole = ((val1 & 0x7f) << 8) + + ((val0 & 0x7f) << 1) + + prev_pixel; + + loc_hi = prev_hi; + if(((val1 >> 7) & 1) != 0) { + loc_hi += 0x7f00; + } + if(((val0 >> 7) & 1) != 0) { + loc_hi += 0xfe; + } + + prev_pixel = (val1 >> 6) & 1; + prev_hi = (val1 >> 7) & 1; + if((x1 + x2 + 2) < 40) { + tmp_val = slow_mem_ptr[0]; + if(tmp_val & 1) { + val_whole |= 0x8000; + } + if(tmp_val & 0x80) { + loc_hi |= 0x8000; + } + } + + loc_hi = loc_hi >> 1; + + for(j = 0; j < 7; j++) { + tmp_val = val_whole & 0xf; + val_hi = loc_hi & 0x3; + + pix_val = g_hires_convert[(val_hi<<4) + + tmp_val]; + *img_ptr++ = pix_val + palette_add; + *img_ptr2++ = pix_val + palette_add; + val_whole = val_whole >> 2; + loc_hi = loc_hi >> 2; + } + } + } + } + + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + g_need_redraw = 0; +} + + +void +redraw_changed_dbl_hires(int start_offset, int start_line, int num_lines, + int color, int reparse, byte *screen_data, int pixels_per_line) +{ + if(!color) { + redraw_changed_dbl_hires_color(start_offset, start_line, + num_lines, reparse, screen_data, pixels_per_line); + } else { + redraw_changed_dbl_hires_bw(start_offset, start_line, + num_lines, reparse, screen_data, pixels_per_line); + } +} + + +void +redraw_changed_dbl_hires_bw(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) +{ + word32 *img_ptr, *img_ptr2; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 val0, val1, val2, val3; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 val_whole; + word32 line_mask; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i; + + st_line = start_line; + start_line = start_line >> 3; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] + + start_offset); + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + + if(ch_mask == 0) { + continue; + } + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + for(x1 = 0; x1 < 40; x1 += shift_per) { + + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = slow_mem_ptr[0x10000]; + val1 = slow_mem_ptr[0]; + val2 = slow_mem_ptr[0x10001]; + val3 = slow_mem_ptr[1]; + slow_mem_ptr += 2; + + val_whole = ((val3 & 0x7f) << 21) + + ((val2 & 0x7f) << 14) + + ((val1 & 0x7f) << 7) + + (val0 & 0x7f); + + tmp0 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp1 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp2 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp3 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp4 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp5 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp6 = g_bw_dhires_convert[val_whole & 0xf]; + + img_ptr[0] = tmp0 + palette_add; + img_ptr[1] = tmp1 + palette_add; + img_ptr[2] = tmp2 + palette_add; + img_ptr[3] = tmp3 + palette_add; + img_ptr[4] = tmp4 + palette_add; + img_ptr[5] = tmp5 + palette_add; + img_ptr[6] = tmp6 + palette_add; + + img_ptr2[0] = tmp0 + palette_add; + img_ptr2[1] = tmp1 + palette_add; + img_ptr2[2] = tmp2 + palette_add; + img_ptr2[3] = tmp3 + palette_add; + img_ptr2[4] = tmp4 + palette_add; + img_ptr2[5] = tmp5 + palette_add; + img_ptr2[6] = tmp6 + palette_add; + + img_ptr += 7; + img_ptr2 += 7; + } + } + } + + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + g_need_redraw = 0; +} + +void +redraw_changed_dbl_hires_color(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) +{ + word32 *ch_ptr; + word32 *img_ptr, *img_ptr2; + byte *slow_mem_ptr; + byte *b_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 val0, val1, val2, val3; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 val_whole; + word32 prev_val; + word32 line_mask; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i; + + st_line = start_line; + start_line = start_line >> 3; + + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); + + left = 40; + right = 0; + + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] + + start_offset); + + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + + if(ch_mask == 0) { + continue; + } + + /* dbl-hires also depends on adjacent bits, so reparse */ + /* adjacent regions so that if bits on the edge change, */ + /* redrawing is correct */ + ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); + ch_mask = -1; + + shift_per = (1 << SHIFT_PER_CHANGE); + + g_a2_screen_buffer_changed |= line_mask; + + for(x1 = 0; x1 < 40; x1 += shift_per) { + + CH_LOOP_A2_VID(ch_mask, ch_tmp); + + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = slow_mem_ptr[0x10000]; + val1 = slow_mem_ptr[0]; + val2 = slow_mem_ptr[0x10001]; + val3 = slow_mem_ptr[1]; + + prev_val = 0; + if((x1 + x2) > 0) { + prev_val = (slow_mem_ptr[-1] >> 3) &0xf; + } + val_whole = ((val3 & 0x7f) << 25) + + ((val2 & 0x7f) << 18) + + ((val1 & 0x7f) << 11) + + ((val0 & 0x7f) << 4) + prev_val; + + tmp0 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp1 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp2 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp3 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp4 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp5 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + if((x1 + x2 + 2) < 40) { + val_whole += (slow_mem_ptr[0x10002]<<8); + } + tmp6 = g_dhires_convert[val_whole & 0xfff]; + + img_ptr[0] = tmp0 + palette_add; + img_ptr[1] = tmp1 + palette_add; + img_ptr[2] = tmp2 + palette_add; + img_ptr[3] = tmp3 + palette_add; + img_ptr[4] = tmp4 + palette_add; + img_ptr[5] = tmp5 + palette_add; + img_ptr[6] = tmp6 + palette_add; + + img_ptr2[0] = tmp0 + palette_add; + img_ptr2[1] = tmp1 + palette_add; + img_ptr2[2] = tmp2 + palette_add; + img_ptr2[3] = tmp3 + palette_add; + img_ptr2[4] = tmp4 + palette_add; + img_ptr2[5] = tmp5 + palette_add; + img_ptr2[6] = tmp6 + palette_add; + + slow_mem_ptr += 2; + img_ptr += 7; + img_ptr2 += 7; + } + } + } + + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } + + g_need_redraw = 0; +} + +int +video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse) +{ + word32 *word_ptr; + word32 *ch_ptr; + byte *byte_ptr; + word32 ch_mask, mask_per_line; + word32 tmp; + word32 scan, old_scan; + int palette_changed; + int diff0, diff1, diff2; + int val0, val1, val2; + int diffs; + int low_delta, low_color; + int delta; + int full; + int ch_bit_offset, ch_word_offset; + int bits_per_line; + int palette; + int j, k; + + palette_changed = 0; + palette = scan_info & 0xf; + + ch_ptr = &(slow_mem_changed[0x9e00 >> CHANGE_SHIFT]); + ch_bit_offset = (palette << 5) >> SHIFT_PER_CHANGE; + ch_word_offset = ch_bit_offset >> 5; + ch_bit_offset = ch_bit_offset & 0x1f; + bits_per_line = (0x20 >> SHIFT_PER_CHANGE); + mask_per_line = -(1 << (32 - bits_per_line)); + mask_per_line = mask_per_line >> ch_bit_offset; + + ch_mask = ch_ptr[ch_word_offset] & mask_per_line; + ch_ptr[ch_word_offset] &= ~mask_per_line; /* clear the bits */ + + old_scan = g_superhires_scan_save[line]; + scan = (scan_info & 0xfaf) + (g_palette_change_cnt[palette] << 12); + g_superhires_scan_save[line] = scan; + +#if 0 + if(line == 1) { + word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00+palette*0x20]); + printf("y1vrshp, ch:%08x, s:%08x,os:%08x %d = %08x %08x %08x %08x %08x %08x %08x %08x\n", + ch_mask, scan, old_scan, reparse, + word_ptr[0], word_ptr[1], word_ptr[2], word_ptr[3], + word_ptr[4], word_ptr[5], word_ptr[6], word_ptr[7]); + } +#endif + + diffs = reparse | ((scan ^ old_scan) & 0xf0f); + /* we must do full reparse if palette changed for this line */ + + if(!diffs && (ch_mask == 0) && (((scan ^ old_scan) & (~0xf0)) == 0)) { + /* nothing changed, get out fast */ + return 0; + } + + if(ch_mask) { + /* indicates the palette has changed, and other scan lines */ + /* using this palette need to do a full 32-byte compare to */ + /* decide if they need to update or not */ + g_palette_change_cnt[palette]++; + } + + word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00 + palette*0x20]); + for(j = 0; j < 8; j++) { + if(word_ptr[j] != g_saved_line_palettes[line][j]) { + diffs = 1; + break; + } + } + + if(diffs == 0) { + return 0; + } + + /* first, save this word_ptr into saved_line_palettes */ + byte_ptr = (byte *)word_ptr; + for(j = 0; j < 8; j++) { + g_saved_line_palettes[line][j] = word_ptr[j]; + } + + full = g_installed_full_superhires_colormap; + + if(!full && palette == g_a2vid_palette) { + /* construct new color approximations from lores */ + for(j = 0; j < 16; j++) { + tmp = *byte_ptr++; + val2 = (*byte_ptr++) & 0xf; + val0 = tmp & 0xf; + val1 = (tmp >> 4) & 0xf; + low_delta = 0x1000; + low_color = 0x0; + for(k = 0; k < 16; k++) { + diff0 = g_expanded_col_0[k] - val0; + diff1 = g_expanded_col_1[k] - val1; + diff2 = g_expanded_col_2[k] - val2; + if(diff0 < 0) { + diff0 = -diff0; + } + if(diff1 < 0) { + diff1 = -diff1; + } + if(diff2 < 0) { + diff2 = -diff2; + } + delta = diff0 + diff1 + diff2; + if(delta < low_delta) { + low_delta = delta; + low_color = k; + } + } + + g_a2vid_palette_remap[j] = low_color; + } + } + + byte_ptr = (byte *)word_ptr; + /* this palette has changed */ + for(j = 0; j < 16; j++) { + val0 = *byte_ptr++; + val1 = *byte_ptr++; + video_update_color_array(palette*16 + j, (val1<<8) + val0); + } + + g_palette_change_summary = 1; + + return 1; +} + +#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_8 +#define SUPER_FILL 0 +#define SUPER_PIXEL_SIZE 8 +#include "superhires.h" +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE + +#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_16 +#define SUPER_FILL 0 +#define SUPER_PIXEL_SIZE 16 +#include "superhires.h" +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE + +#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_32 +#define SUPER_FILL 0 +#define SUPER_PIXEL_SIZE 32 +#include "superhires.h" +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE + +#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_8 +#define SUPER_FILL 1 +#define SUPER_PIXEL_SIZE 8 +#include "superhires.h" +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE + +#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_16 +#define SUPER_FILL 1 +#define SUPER_PIXEL_SIZE 16 +#include "superhires.h" +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE + +#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_32 +#define SUPER_FILL 1 +#define SUPER_PIXEL_SIZE 32 +#include "superhires.h" +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE + + + +void +redraw_changed_super_hires(int start_offset, int start_line, int num_lines, + int in_reparse, byte *screen_data) +{ + word32 *ch_ptr; + word32 mask_per_line; + word32 all_checks; + word32 check0, check1, mask0, mask1; + word32 this_check; + word32 tmp; + word32 line_mask; + word32 pal; + word32 scan, old_scan; + word32 kd_tmp_debug; + int y; + int bits_per_line; + int a2vid_palette; + int type; + int left, right; + int st_line; + int check_bit_pos, check_word_off; + int pixel_size, pixel_size_type; + int use_a2vid_palette, mode_640; + int pixels_per_line; + int ret; + int i; + + st_line = start_line; + start_line = start_line >> 3; + + pixel_size = g_kimage_superhires.mdepth; + pixels_per_line = g_kimage_superhires.width_act; + + pixel_size_type = (pixel_size >> 3) - 1; + /* pixel_size_type is now: 0=8bit, 1=16bit, 3=32bit */ + if(pixel_size_type >= 3) { + pixel_size_type = 2; + } + + kd_tmp_debug = g_a2_screen_buffer_changed; + + line_mask = 1 << (start_line); + + ch_ptr = &(slow_mem_changed[(0x2000) >> CHANGE_SHIFT]); + bits_per_line = 160 >> SHIFT_PER_CHANGE; + mask_per_line = -(1 << (32 - bits_per_line)); + + if(SHIFT_PER_CHANGE != 3) { + halt_printf("SHIFT_PER_CHANGE must be 3!\n"); + return; + } + + a2vid_palette = g_a2vid_palette; + if(g_installed_full_superhires_colormap) { + a2vid_palette = -1; + } else { + /* handle palette counting for finding least-used palette */ + if(pixel_size == 8) { + for(y = 8*start_line; y < 8*(start_line + 1); y++) { + scan = g_slow_memory_ptr[0x19d00 + y]; + pal = scan & 0xf; + g_shr_palette_used[pal]++; + } + } + } + + all_checks = 0; + check0 = 0; + check1 = 0; + for(y = st_line; y < (st_line + num_lines); y++) { + scan = g_slow_memory_ptr[0x19d00 + y]; + check_bit_pos = bits_per_line * y; + check_word_off = check_bit_pos >> 5; /* 32 bits per word */ + check_bit_pos = check_bit_pos & 0x1f; /* 5-bit bit_pos */ + check0 = ch_ptr[check_word_off]; + check1 = ch_ptr[check_word_off+1]; + mask0 = mask_per_line >> check_bit_pos; + mask1 = 0; + this_check = check0 << check_bit_pos; + /* move indicated bit to MSbit position */ + if((check_bit_pos + bits_per_line) > 32) { + this_check |= (check1 >> (32 - check_bit_pos)); + mask1 = mask_per_line << (32 - check_bit_pos); + } + + ch_ptr[check_word_off] = check0 & ~mask0; + ch_ptr[check_word_off+1] = check1 & ~mask1; + + this_check = this_check & mask_per_line; + old_scan = g_superhires_scan_save[y]; + use_a2vid_palette = ((scan & 0xf) == (word32)a2vid_palette); + scan = (scan + (a2vid_palette << 8)) & 0xfff; + + ret = video_rebuild_super_hires_palette(scan, y, in_reparse); +#if 0 + if(y == 1) { + printf("y1, ch:%08x, ret:%d, scan:%03x, os:%03x\n", + this_check, ret, scan, old_scan); + } +#endif + if(ret || in_reparse || ((scan ^ old_scan) & 0xa0)) { + /* 0x80 == mode640, 0x20 = fill */ + this_check = -1; + } + + if(this_check == 0) { + continue; + } + + mode_640 = (scan & 0x80); + if(mode_640) { + g_num_lines_superhires640++; + } + + type = ((scan >> 5) & 1) + (pixel_size_type << 1); + if(type & 1) { + /* fill mode--redraw whole line */ + this_check = -1; + } + + all_checks |= this_check; + + g_a2_screen_buffer_changed |= line_mask; + + + switch(type) { + case 0: /* nofill, 8 bit pixels */ + redraw_changed_super_hires_oneline_nofill_8( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 1: /* fill, 8 bit pixels */ + redraw_changed_super_hires_oneline_fill_8( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 2: /* nofill, 16 bit pixels */ + redraw_changed_super_hires_oneline_nofill_16( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 3: /* fill, 16 bit pixels */ + redraw_changed_super_hires_oneline_fill_16( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 4: /* nofill, 32 bit pixels */ + redraw_changed_super_hires_oneline_nofill_32( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 5: /* fill, 32 byte pixels */ + redraw_changed_super_hires_oneline_fill_32( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + default: + halt_printf("type: %d bad!\n", type); + } + } + + left = 4*40; + right = 0; + + tmp = all_checks; + if(all_checks) { + for(i = 0; i < 160; i += 8) { + if(tmp & 0x80000000) { + left = MIN(i, left); + right = MAX(i + 8, right); + } + tmp = tmp << 1; + } + } + + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = 4*left; + g_a2_line_right_edge[st_line + i] = 4*right; + } + +#if 0 + if((g_a2_screen_buffer_changed & (1 << start_line)) != 0) { + if(((g_full_refresh_needed & (1 << start_line)) == 0) && + left >= right) { + halt_printf("shr: line: %d, left: %d, right:%d\n", + start_line, left, right); + printf("mask_per_line: %08x, all_checks: %08x\n", + mask_per_line, all_checks); + printf("check0,1 = %08x,%08x\n", check0, check1); + printf("a2_screen_chang: %08x\n", kd_tmp_debug); +#ifdef HPUX + U_STACK_TRACE(); +#endif + } + } +#endif + + g_need_redraw = 0; +} + +void +display_screen() +{ + video_update_through_line(262); +} + +void +video_update_event_line(int line) +{ + int new_line; + + video_update_through_line(line); + + new_line = line + g_line_ref_amt; + if(new_line < 200) { + if(!g_config_control_panel) { + add_event_vid_upd(new_line); + } + } else if(line >= 262) { + video_update_through_line(0); + if(!g_config_control_panel) { + add_event_vid_upd(1); /* add event for new screen */ + } + } +} + +void +video_update_through_line(int line) +{ + register word32 start_time; + register word32 end_time; + int *mode_ptr; + word32 mask; + int last_line, num_lines; + int must_reparse; + int new_all_stat, prev_all_stat; + int new_stat, prev_stat; + int i; + +#if 0 + vid_printf("\nvideo_upd for line %d, lines: %06x\n\n", line, + get_lines_since_vbl(g_cur_dcycs)); +#endif + + GET_ITIMER(start_time); + + video_update_all_stat_through_line(line); + + i = g_vid_update_last_line; + + last_line = MIN(200, line+1); /* go through line, but not past 200 */ + + prev_stat = -2; + prev_all_stat = -2; + num_lines = 0; + must_reparse = 0; + for(i = g_vid_update_last_line; i < last_line; i++) { + new_all_stat = g_a2_new_all_stat[i]; + if(new_all_stat != g_a2_cur_all_stat[i]) { + /* regen line_stat for this line */ + g_a2_cur_all_stat[i] = new_all_stat; + if(new_all_stat == prev_all_stat) { + /* save a lookup */ + new_stat = prev_stat; + } else { + new_stat = video_all_stat_to_line_stat(i, + new_all_stat); + } + if(new_stat != g_a2_line_stat[i]) { + /* status changed */ + g_a2_line_stat[i] = new_stat; + mode_ptr = video_update_kimage_ptr(i, new_stat); + if(mode_ptr[i] != new_stat) { + must_reparse = 1; + mode_ptr[i] = new_stat; + } + mask = 1 << (line >> 3); + g_full_refresh_needed |= mask; + g_a2_screen_buffer_changed |= mask; + } + } + + new_stat = g_a2_line_stat[i]; + + if( ((new_stat == prev_stat) && ((i & 7) != 0)) || + (num_lines == 0) ) { + /* merge prev and this together */ + prev_stat = new_stat; + num_lines++; + continue; + } + + /* else, we must call refresh */ + video_refresh_lines(i - num_lines, num_lines, must_reparse); + num_lines = 1; + prev_all_stat = -1; + prev_stat = new_stat; + must_reparse = 0; + } + if(num_lines > 0) { + video_refresh_lines(i - num_lines, num_lines, must_reparse); + } + + g_vid_update_last_line = last_line; + + /* deal with border */ + if(line >= 262) { + if(g_num_lines_prev_superhires != g_num_lines_superhires) { + /* switched in/out from superhires--refresh borders */ + g_border_sides_refresh_needed = 1; + } + refresh_border(); + + if(g_status_refresh_needed) { + g_status_refresh_needed = 0; + x_redraw_status_lines(); + } + } + GET_ITIMER(end_time); + + g_cycs_in_refresh_line += (end_time - start_time); + + if(line >= 262) { + GET_ITIMER(start_time); + if(g_palette_change_summary) { + g_palette_change_summary = 0; + video_update_colormap(); + } + + video_push_kimages(); + GET_ITIMER(end_time); + g_cycs_in_refresh_ximage += (end_time - start_time); + + g_num_lines_prev_superhires = g_num_lines_superhires; + g_num_lines_prev_superhires640 = g_num_lines_superhires640; + g_num_lines_superhires = 0; + g_num_lines_superhires640 = 0; + } +} + +void +video_refresh_lines(int st_line, int num_lines, int must_reparse) +{ + byte *ptr; + int line; + int stat; + int mode; + int dbl, page, color; + int altchar, bg_color, text_color; + int pixels_per_line; + int i; + + line = st_line; + + /* do some basic checking, num_lines should be 1-8, and */ + /* st_line+num_lines-1 cannot roll over 8 */ + if((num_lines < 1) || (num_lines > 8) || + (((st_line & 7) + num_lines) > 8) ) { + halt_printf("video_refresh_lines called with %d, %d\n", + st_line, num_lines); + return; + } + + stat = g_a2_line_stat[line]; + ptr = g_a2_line_kimage[line]->data_ptr; + pixels_per_line = g_a2_line_kimage[line]->width_act; + + /* do not zero g_a2_line_left/right_edge here since text/gr routs */ + /* need to leave stale values around for drawing to work correctly */ + /* all routs force in new left/right when there are screen changes */ + + dbl = stat & 1; + color = (stat >> 1) & 1; + page = (stat >> 2) & 1; + mode = (stat >> 4) & 7; + +#if 0 + printf("refresh line: %d, stat: %04x\n", line, stat); +#endif + + switch(mode) { + case MODE_TEXT: + altchar = (stat >> 7) & 1; + bg_color = (stat >> 8) & 0xf; + text_color = (stat >> 12) & 0xf; + if(dbl) { + redraw_changed_text_80(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, altchar, bg_color, + text_color, pixels_per_line); + } else { + redraw_changed_text_40(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, altchar, bg_color, + text_color, pixels_per_line); + } + break; + case MODE_GR: + if(dbl) { + redraw_changed_dbl_gr(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, pixels_per_line); + } else { + redraw_changed_gr(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, pixels_per_line); + } + break; + case MODE_HGR: + if(dbl) { + redraw_changed_dbl_hires(0x000 + page*0x2000, st_line, + num_lines, color, must_reparse, ptr, + pixels_per_line); + } else { + redraw_changed_hires(0x000 + page*0x2000, st_line, + num_lines, color, must_reparse, ptr, + pixels_per_line); + } + break; + case MODE_SUPER_HIRES: + g_num_lines_superhires++; + redraw_changed_super_hires(0, st_line, num_lines, + must_reparse, ptr); + break; + case MODE_BORDER: + if(line < 192) { + halt_printf("Border line not 192: %d\n", line); + } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[line + i] = 0; + g_a2_line_right_edge[line + i] = 560; + } + if(g_border_line24_refresh_needed) { + g_border_line24_refresh_needed = 0; + g_a2_screen_buffer_changed |= (1 << 24); + } + break; + default: + halt_printf("refresh screen: mode: 0x%02x unknown!\n", mode); + exit(7); + } +} + +void +refresh_border() +{ + /**ZZZZ***/ +} + +void +end_screen() +{ + printf("In end_screen\n"); + xdriver_end(); +} + +byte g_font_array[256][8] = { +#include "kegsfont.h" +}; + +void +read_a2_font() +{ + byte *f40_e_ptr; + byte *f40_o_ptr; + byte *f80_0_ptr, *f80_1_ptr, *f80_2_ptr, *f80_3_ptr; + int char_num; + int j, k; + int val0; + int mask; + int pix; + + for(char_num = 0; char_num < 0x100; char_num++) { + for(j = 0; j < 8; j++) { + val0 = g_font_array[char_num][j]; + + mask = 0x80; + + for(k = 0; k < 3; k++) { + g_font80_off0_bits[char_num][j][k] = 0; + g_font80_off1_bits[char_num][j][k] = 0; + g_font80_off2_bits[char_num][j][k] = 0; + g_font80_off3_bits[char_num][j][k] = 0; + g_font40_even_bits[char_num][j][k] = 0; + g_font40_odd_bits[char_num][j][k] = 0; + } + g_font40_even_bits[char_num][j][3] = 0; + g_font40_odd_bits[char_num][j][3] = 0; + + f40_e_ptr = (byte *)&g_font40_even_bits[char_num][j][0]; + f40_o_ptr = (byte *)&g_font40_odd_bits[char_num][j][0]; + + f80_0_ptr = (byte *)&g_font80_off0_bits[char_num][j][0]; + f80_1_ptr = (byte *)&g_font80_off1_bits[char_num][j][0]; + f80_2_ptr = (byte *)&g_font80_off2_bits[char_num][j][0]; + f80_3_ptr = (byte *)&g_font80_off3_bits[char_num][j][0]; + + for(k = 0; k < 7; k++) { + pix = 0; + if(val0 & mask) { + pix = 0xf; + } + + f40_e_ptr[2*k] = pix; + f40_e_ptr[2*k+1] = pix; + + f40_o_ptr[2*k+2] = pix; + f40_o_ptr[2*k+3] = pix; + + f80_0_ptr[k] = pix; + f80_1_ptr[k+1] = pix; + f80_2_ptr[k+2] = pix; + f80_3_ptr[k+3] = pix; + + mask = mask >> 1; + } + } + } +} + + +/* Helper routine for the *driver.c files */ + +void +video_get_kimage(Kimage *kimage_ptr, int extend_info, int depth, int mdepth) +{ + int width; + int height; + + width = A2_WINDOW_WIDTH; + height = A2_WINDOW_HEIGHT; + if(extend_info & 1) { + /* Border at top and bottom of screen */ + width = X_A2_WINDOW_WIDTH; + height = X_A2_WINDOW_HEIGHT - A2_WINDOW_HEIGHT + 2*8; + } + if(extend_info & 2) { + /* Border at sides of screen */ + width = BORDER_WIDTH + EFF_BORDER_WIDTH; + height = A2_WINDOW_HEIGHT; + } + + kimage_ptr->dev_handle = 0; + kimage_ptr->dev_handle2 = 0; + kimage_ptr->data_ptr = 0; + kimage_ptr->width_req = width; + kimage_ptr->width_act = width; + kimage_ptr->height = height; + kimage_ptr->depth = depth; + kimage_ptr->mdepth = mdepth; + kimage_ptr->aux_info = 0; + + x_get_kimage(kimage_ptr); +} + +void +video_get_kimages() +{ + video_get_kimage(&g_kimage_text[0], 0, 8, 8); + video_get_kimage(&g_kimage_text[1], 0, 8, 8); + video_get_kimage(&g_kimage_hires[0], 0, 8, 8); + video_get_kimage(&g_kimage_hires[1], 0, 8, 8); + video_get_kimage(&g_kimage_superhires, 0, g_screen_depth, + g_screen_mdepth); + video_get_kimage(&g_kimage_border_special, 1, g_screen_depth, + g_screen_mdepth); + video_get_kimage(&g_kimage_border_sides, 2, g_screen_depth, + g_screen_mdepth); +} + +void +video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx, + int starty, int width, int height) +{ + byte *indata, *inptr; + word32 *outdata32, *outptr32; + word16 *outdata16, *outptr16; + word32 *palptr; + int out_width, in_width; + int x, y; + + indata = (byte *)kim_in->data_ptr; + outdata32 = (word32 *)kim_out->data_ptr; + outdata16 = (word16 *)kim_out->data_ptr; + + if(kim_in == &g_kimage_superhires) { + palptr = &(g_palette_8to1624[0]); + } else { + palptr = &(g_a2palette_8to1624[0]); + } + if(kim_in->depth != 8) { + printf("x_convert_kimage_depth from non-8 bit depth: %p\n", + kim_in); + exit(1); + } + + out_width = kim_out->width_act; + in_width = kim_in->width_act; + indata += (starty * in_width + startx); + outdata32 += (starty * out_width + startx); + outdata16 += (starty * out_width + startx); + if(kim_out->mdepth == 16) { + for(y = 0; y < height; y++) { + outptr16 = outdata16; + inptr = indata; + for(x = 0; x < width; x++) { + *outptr16++ = palptr[*inptr++]; + } + outdata16 += out_width; + indata += in_width; + } + } else { + /* 32-bit depth */ + for(y = 0; y < height; y++) { + outptr32 = outdata32; + inptr = indata; + for(x = 0; x < width; x++) { + *outptr32++ = palptr[*inptr++]; + } + outdata32 += out_width; + indata += in_width; + } + } +} + +void +video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, + int right_pix) +{ + int mdepth_mismatch; + int srcy; + + if(left_pix >= right_pix || left_pix < 0 || right_pix <= 0) { + halt_printf("video_push_lines: lines %d to %d, pix %d to %d\n", + start_line, end_line, left_pix, right_pix); + printf("a2_screen_buf_ch:%08x, g_full_refr:%08x\n", + g_a2_screen_buffer_changed, g_full_refresh_needed); + } + + srcy = 2*start_line; + + mdepth_mismatch = (kimage_ptr->mdepth != g_screen_mdepth); + if(mdepth_mismatch) { + /* translate from 8-bit pseudo to correct visual */ + video_convert_kimage_depth(kimage_ptr, &g_mainwin_kimage, + left_pix, srcy, (right_pix - left_pix), + 2*(end_line - start_line)); + kimage_ptr = &g_mainwin_kimage; + } + g_refresh_bytes_xfer += 2*(end_line - start_line) * + (right_pix - left_pix); + + + x_push_kimage(kimage_ptr, BASE_MARGIN_LEFT + left_pix, + BASE_MARGIN_TOP + srcy, left_pix, srcy, + (right_pix - left_pix), 2*(end_line - start_line)); +} + +void +video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line, + int end_line) +{ + Kimage *kimage_ptr; + int srcy; + + if(start_line < 0 || width < 0) { + return; + } + +#if 0 + printf("push_border_sides lines:%d-%d from %d to %d\n", + start_line, end_line, end_x - width, end_x); +#endif + kimage_ptr = &g_kimage_border_sides; + g_refresh_bytes_xfer += 2 * (end_line - start_line) * width; + + srcy = 2 * start_line; + x_push_kimage(kimage_ptr, dest_x, BASE_MARGIN_TOP + srcy, + src_x, srcy, width, 2*(end_line - start_line)); +} + +void +video_push_border_sides() +{ + int old_width; + int prev_line; + int width; + int mode; + int i; + +#if 0 + printf("refresh border sides!\n"); +#endif + + /* redraw left sides */ + video_push_border_sides_lines(0, 0, BORDER_WIDTH, 0, 200); + + /* right side--can be "jagged" */ + prev_line = -1; + old_width = -1; + for(i = 0; i < 200; i++) { + mode = (g_a2_line_stat[i] >> 4) & 7; + width = EFF_BORDER_WIDTH; + if(mode == MODE_SUPER_HIRES) { + width = BORDER_WIDTH; + } + if(width != old_width) { + video_push_border_sides_lines(BORDER_WIDTH, + X_A2_WINDOW_WIDTH - old_width, old_width, + prev_line, i); + prev_line = i; + old_width = width; + } + } + + video_push_border_sides_lines(BORDER_WIDTH, + X_A2_WINDOW_WIDTH - old_width, old_width, prev_line, 200); +} + +void +video_push_border_special() +{ + Kimage *kimage_ptr; + int width, height; + + width = X_A2_WINDOW_WIDTH; + height = BASE_MARGIN_TOP; + + kimage_ptr = &g_kimage_border_special; + g_refresh_bytes_xfer += width * (BASE_MARGIN_TOP + BASE_MARGIN_BOTTOM); + + x_push_kimage(kimage_ptr, 0, BASE_MARGIN_TOP + A2_WINDOW_HEIGHT, + 0, 0, width, BASE_MARGIN_BOTTOM); + x_push_kimage(kimage_ptr, 0, 0, + 0, BASE_MARGIN_BOTTOM, width, BASE_MARGIN_TOP); + +} + +void +video_push_kimages() +{ + register word32 start_time; + register word32 end_time; + Kimage *last_kim, *cur_kim; + word32 mask; + int start; + int line; + int left_pix, right_pix; + int left, right; + int line_div8; + + if(g_border_sides_refresh_needed) { + g_border_sides_refresh_needed = 0; + video_push_border_sides(); + } + if(g_border_special_refresh_needed) { + g_border_special_refresh_needed = 0; + video_push_border_special(); + } + + if(g_a2_screen_buffer_changed == 0) { + return; + } + + GET_ITIMER(start_time); + + start = -1; + last_kim = (Kimage *)-1; + cur_kim = (Kimage *)0; + + left_pix = 640; + right_pix = 0; + + for(line = 0; line < 200; line++) { + line_div8 = line >> 3; + mask = 1 << (line_div8); + cur_kim = g_a2_line_kimage[line]; + if((g_full_refresh_needed & mask) != 0) { + left = 0; + right = 560; + if(cur_kim == &g_kimage_superhires) { + right = 640; + } + } else { + left = g_a2_line_left_edge[line]; + right = g_a2_line_right_edge[line]; + } + + if(!(g_a2_screen_buffer_changed & mask) || (left > right)) { + /* No need to update this line */ + /* Refresh previous chunks of lines, if any */ + if(start >= 0) { + video_push_lines(last_kim, start, line, + left_pix, right_pix); + start = -1; + left_pix = 640; + right_pix = 0; + } + } else { + /* Need to update this line */ + if(start < 0) { + start = line; + last_kim = cur_kim; + } + if(cur_kim != last_kim) { + /* do the refresh */ + video_push_lines(last_kim, start, line, + left_pix, right_pix); + last_kim = cur_kim; + start = line; + left_pix = left; + right_pix = right; + } + left_pix = MIN(left, left_pix); + right_pix = MAX(right, right_pix); + } + } + + if(start >= 0) { + video_push_lines(last_kim, start, 200, left_pix, right_pix); + } + + g_a2_screen_buffer_changed = 0; + g_full_refresh_needed = 0; + + x_push_done(); + + GET_ITIMER(end_time); + + g_cycs_in_xredraw += (end_time - start_time); +} + + +void +video_update_color_raw(int col_num, int a2_color) +{ + word32 tmp; + int red, green, blue; + int newred, newgreen, newblue; + + red = (a2_color >> 8) & 0xf; + green = (a2_color >> 4) & 0xf; + blue = (a2_color) & 0xf; + red = ((red << 4) + red); + green = ((green << 4) + green); + blue = ((blue << 4) + blue); + + newred = red >> g_red_right_shift; + newgreen = green >> g_green_right_shift; + newblue = blue >> g_blue_right_shift; + + tmp = ((newred & g_red_mask) << g_red_left_shift) + + ((newgreen & g_green_mask) << g_green_left_shift) + + ((newblue & g_blue_mask) << g_blue_left_shift); + g_palette_8to1624[col_num] = tmp; + + x_update_color(col_num, red, green, blue, tmp); +} + +void +video_update_color_array(int col_num, int a2_color) +{ + int palette; + int full; + + if(col_num >= 256 || col_num < 0) { + halt_printf("video_update_color_array: col: %03x\n", col_num); + return; + } + + full = g_installed_full_superhires_colormap; + + palette = col_num >> 4; + if(!full && palette == g_a2vid_palette) { + return; + } + +#if 0 + if(g_screen_depth != 8) { + /* redraw whole superhires for now */ + g_full_refresh_needed = -1; + } +#endif + + video_update_color_raw(col_num, a2_color); +} + +void +video_update_colormap() +{ + int palette; + int full; + int i; + + full = g_installed_full_superhires_colormap; + + if(!full) { + palette = g_a2vid_palette << 4; + for(i = 0; i < 16; i++) { + video_update_color_raw(palette + i, g_lores_colors[i]); + } + x_update_physical_colormap(); + } +} + +void +video_update_status_line(int line, const char *string) +{ + char *buf; + const char *ptr; + int i; + + if(line >= MAX_STATUS_LINES || line < 0) { + printf("update_status_line: line: %d!\n", line); + exit(1); + } + + ptr = string; + buf = &(g_status_buf[line][0]); + g_status_ptrs[line] = buf; + for(i = 0; i < STATUS_LINE_LENGTH; i++) { + if(*ptr) { + buf[i] = *ptr++; + } else { + buf[i] = ' '; + } + } + + buf[STATUS_LINE_LENGTH] = 0; +} + +void +video_show_debug_info() +{ + word32 tmp1; + + printf("g_cur_dcycs: %f, last_vbl: %f\n", g_cur_dcycs, + g_last_vbl_dcycs); + tmp1 = get_lines_since_vbl(g_cur_dcycs); + printf("lines since vbl: %06x\n", tmp1); + printf("Last line updated: %d\n", g_vid_update_last_line); +} diff --git a/src/win32.rc b/src/win32.rc new file mode 100644 index 0000000..f4b5f2e --- /dev/null +++ b/src/win32.rc @@ -0,0 +1,109 @@ +#include +#include "winresource.h" + +// $Id: $ + +#ifndef IDC_STATIC +#define IDC_STATIC (-1) +#endif + +IDD_DLG_DISKCONF DIALOGEX 0, 0, 268, 182 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disk Configuration" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,150,161,50,14 + PUSHBUTTON "Cancel",IDCANCEL,203,161,50,14 + LTEXT "S5D1",IDC_STATIC,19,46,19,8 + EDITTEXT IDC_EDIT_S5D1,43,42,156,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S5D1,203,42,50,14 + LTEXT "S5D2",IDC_STATIC,19,62,19,8 + EDITTEXT IDC_EDIT_S5D2,43,60,155,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_BTN_S5D2,203,60,50,14 + LTEXT "S6D1",IDC_STATIC,19,80,19,8 + EDITTEXT IDC_EDIT_S6D1,43,77,156,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_BTN_S6D1,203,77,50,14 + LTEXT "S6D2",IDC_STATIC,19,98,19,8 + EDITTEXT IDC_EDIT_S6D2,43,95,156,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_BTN_S6D2,203,96,50,14 + LTEXT "S7D1",IDC_STATIC,19,118,19,8 + EDITTEXT IDC_EDIT_S7D1,43,115,155,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_BTN_S7D1,203,115,50,14 + LTEXT "S7D2",IDC_STATIC,19,137,19,8 + EDITTEXT IDC_EDIT_S7D2,43,135,155,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse",IDC_BTN_S7D2,203,135,50,14 + GROUPBOX "Disk settings",IDC_STATIC,7,7,254,148 + LTEXT "Configure your disk images for each drive. Disk image formats supported\nare *.2MG,*.PO and *.DSK. ", + IDC_STATIC,19,20,234,16 +END + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_KEGS32 MENU DISCARDABLE +BEGIN + POPUP "&Emulator" + BEGIN + MENUITEM "&Set Disk Configuration\tALT-F1", ID_FILE_DISK + MENUITEM "Send CTRL Open-Apple Reset\tCTRL-ALT-BREAK", + ID_FILE_SENDRESET + MENUITEM "Toggle &Joystick", ID_FILE_JOYSTICK + MENUITEM "Toggle Debug Statistics", ID_FILE_DEBUGSTAT + MENUITEM SEPARATOR + MENUITEM "E&xit\tALT-F4", ID_FILE_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About", ID_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDR_TOOLBAR BITMAP DISCARDABLE "wintoolbar.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCEL ACCELERATORS DISCARDABLE +BEGIN + VK_F1, ID_FILE_DISK, VIRTKEY, ALT, NOINVERT + VK_F4, ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT +END + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDC_KEGS32 ICON DISCARDABLE "win32.ico" +KEGS32_ICON ICON DISCARDABLE "win32.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT_DIALOG DIALOG DISCARDABLE 0, 0, 207, 82 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,78,61,50,14 + LTEXT "KEGS32: GS Emulator.\nBased on KEGS by Kent Dickey\nWindows Port by Chea Chee Keong\n\nThis software is free for non-commercial use.", + IDC_STATIC,38,7,162,45,NOT WS_GROUP + ICON "KEGS32_ICON",IDC_STATIC,7,7,21,20,0 +END + + diff --git a/src/win32snd_driver.c b/src/win32snd_driver.c new file mode 100644 index 0000000..e3e74a4 --- /dev/null +++ b/src/win32snd_driver.c @@ -0,0 +1,215 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_win32snd_driver_c[] = "@(#)$KmKId: win32snd_driver.c,v 1.5 2002-11-19 03:09:59-05 kadickey Exp $"; + +#include "defc.h" +#include "sound.h" + +#ifndef __CYGWIN__ +# include +# include +#endif +#include + +extern int Verbose; + +extern int g_audio_rate; + +unsigned int __stdcall child_sound_loop_win32(void *param); +void check_wave_error(int res, char *str); + +#define NUM_WAVE_HEADERS 8 + +#ifndef __CYGWIN__ +HWAVEOUT g_wave_handle; +WAVEHDR g_wavehdr[NUM_WAVE_HEADERS]; +#endif + +extern int g_audio_enable; +extern word32 *g_sound_shm_addr; +extern int g_preferred_rate; + +int g_win32snd_buflen = 0x1000; + +void +win32snd_init(word32 *shmaddr) +{ + printf("win32snd_init\n"); + child_sound_loop(-1, -1, shmaddr); + + return; +} + +void +win32snd_shutdown() +{ + /* hmm */ + +} + +#ifndef __CYGWIN__ + +void CALLBACK +handle_wav_snd(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, + DWORD dwParam2) +{ + LPWAVEHDR lpwavehdr; + + /* Only service "buffer done playing messages */ + if(uMsg == WOM_DONE) { + lpwavehdr = (LPWAVEHDR)dwParam1; + if(lpwavehdr->dwFlags == (WHDR_DONE | WHDR_PREPARED)) { + lpwavehdr->dwUser = FALSE; + } + } + + return; +} +void +check_wave_error(int res, char *str) +{ + char buf[256]; + + if(res == MMSYSERR_NOERROR) { + return; + } + + waveOutGetErrorText(res, &buf[0], sizeof(buf)); + printf("%s: %s\n", str, buf); + exit(1); +} + +void +child_sound_init_win32() +{ + WAVEFORMATEX wavefmt; + WAVEOUTCAPS caps; + byte *bptr; + int bits_per_sample, channels, block_align; + int blen; + int res; + int i; + + memset(&wavefmt, 0, sizeof(WAVEFORMATEX)); + + wavefmt.wFormatTag = WAVE_FORMAT_PCM; + bits_per_sample = 16; + channels = 2; + wavefmt.wBitsPerSample = bits_per_sample; + wavefmt.nChannels = channels; + wavefmt.nSamplesPerSec = g_audio_rate; + block_align = channels * (bits_per_sample / 8); + wavefmt.nBlockAlign = block_align; + wavefmt.nAvgBytesPerSec = block_align * g_audio_rate; + + res = waveOutOpen(&g_wave_handle, WAVE_MAPPER, &wavefmt, 0, 0, + WAVE_FORMAT_QUERY); + + if(res != MMSYSERR_NOERROR) { + printf("Cannot open audio device\n"); + g_audio_enable = 0; + return; + } + + res = waveOutOpen(&g_wave_handle, WAVE_MAPPER, &wavefmt, + (DWORD)handle_wav_snd, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC); + + if(res != MMSYSERR_NOERROR) { + printf("Cannot register audio\n"); + g_audio_enable = 0; + return; + } + + g_audio_rate = wavefmt.nSamplesPerSec; + + blen = (SOUND_SHM_SAMP_SIZE * 4 * 2) / NUM_WAVE_HEADERS; + g_win32snd_buflen = blen; + bptr = malloc(blen * NUM_WAVE_HEADERS); + if(bptr == NULL) { + printf("Unabled to allocate sound buffer\n"); + exit(1); + } + + for(i = 0; i < NUM_WAVE_HEADERS; i++) { + memset(&g_wavehdr[i], 0, sizeof(WAVEHDR)); + g_wavehdr[i].dwUser = FALSE; + g_wavehdr[i].lpData = &(bptr[i*blen]); + g_wavehdr[i].dwBufferLength = blen; + g_wavehdr[i].dwFlags = 0; + g_wavehdr[i].dwLoops = 0; + res = waveOutPrepareHeader(g_wave_handle, &g_wavehdr[i], + sizeof(WAVEHDR)); + check_wave_error(res, "waveOutPrepareHeader"); + } + + res = waveOutGetDevCaps((UINT)g_wave_handle, &caps, sizeof(caps)); + check_wave_error(res, "waveOutGetDevCaps"); + printf("Using %s\n", caps.szPname); + printf(" Bits per Sample = %d. Channels = %d\n", + wavefmt.wBitsPerSample, wavefmt.nChannels); + printf(" Sampling rate = %d, avg_bytes_per_sec = %d\n", + (int)wavefmt.nSamplesPerSec, (int)wavefmt.nAvgBytesPerSec); + + set_audio_rate(g_audio_rate); + +} + +void +win32_send_audio2(byte *ptr, int size) +{ + int found; + int res; + int i; + + found = 0; + for(i = 0; i < NUM_WAVE_HEADERS; i++) { + if(g_wavehdr[i].dwUser == FALSE) { + found = 1; + break; + } + } + + if(!found) { + /* all audio buffers busy, just get out */ + return; + } + + memcpy(g_wavehdr[i].lpData, ptr, size); + g_wavehdr[i].dwBufferLength = size; + g_wavehdr[i].dwUser = TRUE; + + res = waveOutWrite(g_wave_handle, &g_wavehdr[i], sizeof(g_wavehdr)); + check_wave_error(res, "waveOutWrite"); + + return; +} + +int +win32_send_audio(byte *ptr, int in_size) +{ + int size; + int tmpsize; + + size = in_size; + while(size > 0) { + tmpsize = size; + if(size > g_win32snd_buflen) { + tmpsize = g_win32snd_buflen; + } + win32_send_audio2(ptr, tmpsize); + ptr += tmpsize; + size = size - tmpsize; + } + + return in_size; +} + +#endif /* __CYGWIN */ diff --git a/src/windriver.c b/src/windriver.c new file mode 100644 index 0000000..787c9b6 --- /dev/null +++ b/src/windriver.c @@ -0,0 +1,637 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_windriver_c[] = "@(#)$KmKId: windriver.c,v 1.8 2004-03-23 17:25:37-05 kentd Exp $"; + +#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ +#define STRICT /* Tell Windows we want compile type checks */ + +#include +#include +#include +#include +#include + +#include "defc.h" +#include "protos_windriver.h" + +extern int Verbose; + +extern int g_warp_pointer; +extern int g_screen_depth; +extern int g_force_depth; +int g_screen_mdepth = 0; + +extern int g_quit_sim_now; + +int g_use_shmem = 1; +int g_has_focus = 0; +int g_auto_repeat_on = -1; + +extern Kimage g_mainwin_kimage; + +HDC g_main_dc; +HDC g_main_cdc; +int g_main_height = 0; + +int g_win_capslock_down = 0; + +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; + +extern word32 g_full_refresh_needed; + +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; + +extern int g_lores_colors[]; +extern int g_cur_a2_stat; + +extern int g_a2vid_palette; + +extern int g_installed_full_superhires_colormap; + +extern int g_screen_redraw_skip_amt; + +extern word32 g_a2_screen_buffer_changed; + +HWND g_hwnd_main; +BITMAPINFO *g_bmapinfo_ptr = 0; +volatile BITMAPINFOHEADER *g_bmaphdr_ptr = 0; + +int g_num_a2_keycodes = 0; + +extern char *g_status_ptrs[MAX_STATUS_LINES]; + +int g_win_button_states = 0; + + +/* this table is used to search for the Windows VK_* in col 1 or 2 */ +/* flags bit 8 is or'ed into the VK, so we can distinguish keypad keys */ +/* regardless of numlock */ +int g_a2_key_to_wsym[][3] = { + { 0x35, VK_ESCAPE, 0 }, + { 0x7a, VK_F1, 0 }, + { 0x7b, VK_F2, 0 }, + { 0x63, VK_F3, 0 }, + { 0x76, VK_F4, 0 }, + { 0x60, VK_F5, 0 }, + { 0x61, VK_F6, 0 }, + { 0x62, VK_F7, 0 }, + { 0x64, VK_F8, 0 }, + { 0x65, VK_F9, 0 }, + { 0x6d, VK_F10, 0 }, + { 0x67, VK_F11, 0 }, + { 0x6f, VK_F12, 0 }, + { 0x69, VK_F13, 0 }, + { 0x6b, VK_F14, 0 }, + { 0x71, VK_F15, 0 }, + { 0x7f, VK_PAUSE, VK_CANCEL+0x100 }, + + { 0x32, 0xc0, 0 }, /* '`' */ + { 0x12, '1', 0 }, + { 0x13, '2', 0 }, + { 0x14, '3', 0 }, + { 0x15, '4', 0 }, + { 0x17, '5', 0 }, + { 0x16, '6', 0 }, + { 0x1a, '7', 0 }, + { 0x1c, '8', 0 }, + { 0x19, '9', 0 }, + { 0x1d, '0', 0 }, + { 0x1b, 0xbd, 0 }, /* '-' */ + { 0x18, 0xbb, 0 }, /* '=' */ + { 0x33, VK_BACK, 0 }, /* backspace */ + { 0x72, VK_INSERT+0x100, 0 }, /* Insert key */ +/* { 0x73, XK_Home, 0 }, alias VK_HOME to be KP_Equal! */ + { 0x74, VK_PRIOR+0x100, 0 }, /* pageup */ + { 0x47, VK_NUMLOCK, VK_NUMLOCK+0x100 }, /* clear */ + { 0x51, VK_HOME+0x100, 0 }, /* KP_equal is HOME key */ + { 0x4b, VK_DIVIDE, VK_DIVIDE+0x100 }, + { 0x43, VK_MULTIPLY, VK_MULTIPLY+0x100 }, + + { 0x30, VK_TAB, 0 }, + { 0x0c, 'Q', 0 }, + { 0x0d, 'W', 0 }, + { 0x0e, 'E', 0 }, + { 0x0f, 'R', 0 }, + { 0x11, 'T', 0 }, + { 0x10, 'Y', 0 }, + { 0x20, 'U', 0 }, + { 0x22, 'I', 0 }, + { 0x1f, 'O', 0 }, + { 0x23, 'P', 0 }, + { 0x21, 0xdb, 0 }, /* [ */ + { 0x1e, 0xdd, 0 }, /* ] */ + { 0x2a, 0xdc, 0 }, /* backslash, bar */ + { 0x75, VK_DELETE+0x100, 0 }, + { 0x77, VK_END+0x100, VK_END }, + { 0x79, VK_NEXT+0x100, 0 }, + { 0x59, VK_NUMPAD7, VK_HOME }, + { 0x5b, VK_NUMPAD8, VK_UP }, + { 0x5c, VK_NUMPAD9, VK_PRIOR }, + { 0x4e, VK_SUBTRACT, VK_SUBTRACT+0x100 }, + + // { 0x39, VK_CAPITAL, 0 }, // Handled specially! + { 0x00, 'A', 0 }, + { 0x01, 'S', 0 }, + { 0x02, 'D', 0 }, + { 0x03, 'F', 0 }, + { 0x05, 'G', 0 }, + { 0x04, 'H', 0 }, + { 0x26, 'J', 0 }, + { 0x28, 'K', 0 }, + { 0x25, 'L', 0 }, + { 0x29, 0xba, 0 }, /* ; */ + { 0x27, 0xde, 0 }, /* single quote */ + { 0x24, VK_RETURN, 0 }, + { 0x56, VK_NUMPAD4, VK_LEFT }, + { 0x57, VK_NUMPAD5, VK_CLEAR }, + { 0x58, VK_NUMPAD6, VK_RIGHT }, + { 0x45, VK_ADD, 0 }, + + { 0x38, VK_SHIFT, 0 }, + { 0x06, 'Z', 0 }, + { 0x07, 'X', 0 }, + { 0x08, 'C', 0 }, + { 0x09, 'V', 0 }, + { 0x0b, 'B', 0 }, + { 0x2d, 'N', 0 }, + { 0x2e, 'M', 0 }, + { 0x2b, 0xbc, 0 }, /* , */ + { 0x2f, 0xbe, 0 }, /* . */ + { 0x2c, 0xbf, 0 }, /* / */ + { 0x3e, VK_UP+0x100, 0 }, + { 0x53, VK_NUMPAD1, VK_END }, + { 0x54, VK_NUMPAD2, VK_DOWN }, + { 0x55, VK_NUMPAD3, VK_NEXT }, + + { 0x36, VK_CONTROL, VK_CONTROL+0x100 }, + { 0x3a, VK_SNAPSHOT+0x100, VK_MENU+0x100 },/* Opt=prntscrn or alt-r */ + { 0x37, VK_SCROLL, VK_MENU }, /* Command=scr_lock or alt-l */ + { 0x31, ' ', 0 }, + { 0x3b, VK_LEFT+0x100, 0 }, + { 0x3d, VK_DOWN+0x100, 0 }, + { 0x3c, VK_RIGHT+0x100, 0 }, + { 0x52, VK_NUMPAD0, VK_INSERT }, + { 0x41, VK_DECIMAL, VK_DECIMAL }, + { 0x4c, VK_RETURN+0x100, 0 }, + { -1, -1, -1 } +}; + +int +win_update_mouse(int x, int y, int button_states, int buttons_valid) +{ + int buttons_changed; + + buttons_changed = ((g_win_button_states & buttons_valid) != + button_states); + g_win_button_states = (g_win_button_states & ~buttons_valid) | + (button_states & buttons_valid); + if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && + (y == A2_WINDOW_HEIGHT/2) && (!buttons_changed) ) { + /* tell adb routs to recenter but ignore this motion */ + update_mouse(x, y, 0, -1); + return 0; + } + return update_mouse(x, y, button_states, buttons_valid & 7); +} + +void +win_event_mouse(WPARAM wParam, LPARAM lParam) +{ + POINT pt; + word32 flags; + int buttons; + int x, y; + int motion; + + flags = wParam; + x = LOWORD(lParam) - BASE_MARGIN_LEFT; + y = HIWORD(lParam) - BASE_MARGIN_TOP; + + buttons = (flags & 1) + + (((flags >> 1) & 1) << 2) + + (((flags >> 4) & 1) << 1); +#if 0 + printf("Mouse at %d, %d fl: %08x, but: %d\n", x, y, flags, buttons); +#endif + motion = win_update_mouse(x, y, buttons, 7); + + if(motion && g_warp_pointer) { + /* move mouse to center of screen */ + pt.x = BASE_MARGIN_LEFT + A2_WINDOW_WIDTH/2; + pt.y = BASE_MARGIN_TOP + A2_WINDOW_HEIGHT/2; + ClientToScreen(g_hwnd_main, &pt); + SetCursorPos(pt.x, pt.y); + } +} + +void +win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags) +{ + word32 vk; + int a2code; + int is_up; + int capslock_down; + int i; + + if((flags & 0x4000) && down) { + /* auto-repeating, just ignore it */ + return; + } + + vk = raw_vk + (flags & 0x100); +#if 0 + printf("Key event, vk=%04x, down:%d, repeat: %d, flags: %08x\n", + vk, down, repeat, flags); +#endif + + /* remap a few keys here.. sigh */ + if((vk & 0xff) == VK_APPS) { + /* remap to command */ + vk = VK_MENU; + } + + if((vk & 0xff) == VK_CAPITAL) { + // Windows gives us up-and-down events of the actual key + // Use GetKeyState to get the true toggle state, and pass + // that on to the adb interface + capslock_down = GetKeyState(VK_CAPITAL) & 0x01; + if(capslock_down != g_win_capslock_down) { + g_win_capslock_down = capslock_down; + adb_physical_key_update(0x39, !capslock_down); + } + + return; // Do no more processing! + } + + /* search a2key_to_wsym to find wsym in col 1 or 2 */ + i = 0; + is_up = !down; + for(i = g_num_a2_keycodes-1; i >= 0; i--) { + a2code = g_a2_key_to_wsym[i][0]; + if((vk == g_a2_key_to_wsym[i][1]) || + (vk == g_a2_key_to_wsym[i][2])) { + vid_printf("Found vk:%04x = %02x\n", vk, a2code); + adb_physical_key_update(a2code, is_up); + return; + } + } + printf("VK: %04x unknown\n", vk); +} + +void +win_event_quit(HWND hwnd) +{ + g_quit_sim_now = 1; + my_exit(0); +} + +void +win_event_redraw() +{ + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + g_status_refresh_needed = 1; + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; +} + +LRESULT CALLBACK +win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) +{ + switch(umsg) { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + win_event_mouse(wParam, lParam); + return 0; + case WM_PAINT: + win_event_redraw(); + break; + } + switch(umsg) { + HANDLE_MSG(hwnd, WM_KEYUP, win_event_key); + HANDLE_MSG(hwnd, WM_KEYDOWN, win_event_key); + HANDLE_MSG(hwnd, WM_SYSKEYUP, win_event_key); + HANDLE_MSG(hwnd, WM_SYSKEYDOWN, win_event_key); + HANDLE_MSG(hwnd, WM_DESTROY, win_event_quit); + } + +#if 0 + switch(umsg) { + case WM_NCACTIVATE: + case WM_NCHITTEST: + case WM_NCMOUSEMOVE: + case WM_SETCURSOR: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_CONTEXTMENU: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_PAINT: + + break; + default: + printf("Got umsg2: %d\n", umsg); + } +#endif + + return DefWindowProc(hwnd, umsg, wParam, lParam); +} + + +int +main(int argc, char **argv) +{ + WNDCLASS wndclass; + RECT rect; + int height; + + InitCommonControls(); + + wndclass.style = 0; + wndclass.lpfnWndProc = (WNDPROC)win_event_handler; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = GetModuleHandle(NULL); + wndclass.hIcon = LoadIcon((HINSTANCE)NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = "kegswin"; + + // Register the window + if(!RegisterClass(&wndclass)) { + printf("Registering window failed\n"); + exit(1); + } + + height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES * 16) + 32; + g_main_height = height; + + g_hwnd_main = CreateWindow("kegswin", "KEGSWIN - Apple //gs Emulator", + WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, + X_A2_WINDOW_WIDTH, height, + NULL, NULL, GetModuleHandle(NULL), NULL); + + printf("g_hwnd_main = %p, height = %d\n", g_hwnd_main, height); + GetWindowRect(g_hwnd_main, &rect); + printf("...rect is: %ld, %ld, %ld, %ld\n", rect.left, rect.top, + rect.right, rect.bottom); + + g_main_dc = GetDC(g_hwnd_main); + + SetTextColor(g_main_dc, 0); + SetBkColor(g_main_dc, 0xffffff); + + g_main_cdc = CreateCompatibleDC(g_main_dc); + + g_screen_depth = 24; + g_screen_mdepth = 32; + + + // Call kegsmain + return kegsmain(argc, argv); +} + + +void +check_input_events() +{ + MSG msg; + + while(PeekMessage(&msg, g_hwnd_main, 0, 0, PM_NOREMOVE)) { + if(GetMessage(&msg, g_hwnd_main, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + printf("GetMessage returned <= 0\n"); + my_exit(2); + } + } + + return; +} + + +void +x_update_color(int col_num, int red, int green, int blue, word32 rgb) +{ +} + +void +x_update_physical_colormap() +{ +} + +void +show_xcolor_array() +{ + int i; + + for(i = 0; i < 256; i++) { + printf("%02x: %08x\n", i, g_palette_8to1624[i]); + } +} + + +void +xdriver_end() +{ + printf("xdriver_end\n"); +} + + +void +x_get_kimage(Kimage *kimage_ptr) +{ + byte *ptr; + int width; + int height; + int depth, mdepth; + int size; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + mdepth = kimage_ptr->mdepth; + + size = 0; + if(depth == g_screen_depth) { + /* Use g_bmapinfo_ptr, adjusting width, height */ + g_bmaphdr_ptr->biWidth = width; + g_bmaphdr_ptr->biHeight = -height; + kimage_ptr->dev_handle = CreateDIBSection(g_main_dc, + g_bmapinfo_ptr, DIB_RGB_COLORS, + (VOID **)&(kimage_ptr->data_ptr), NULL, 0); + } else { + /* allocate buffers for video.c to draw into */ + + size = (width*height*mdepth) >> 3; + ptr = (byte *)malloc(size); + + if(ptr == 0) { + printf("malloc for data failed, mdepth: %d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + kimage_ptr->dev_handle = (void *)-1; + + } + printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr, + kimage_ptr->dev_handle, kimage_ptr->data_ptr, size); + + return; +} + + +void +dev_video_init() +{ + int extra_size; + int lores_col; + int a2code; + int i; + + printf("Preparing graphics system\n"); + + g_num_a2_keycodes = 0; + for(i = 0; i < 0x7f; i++) { + a2code = g_a2_key_to_wsym[i][0]; + if(a2code < 0) { + g_num_a2_keycodes = i; + } + } + + g_screen_depth = 24; + g_screen_mdepth = 32; + + extra_size = sizeof(RGBQUAD); + if(g_screen_depth == 8) { + extra_size = 256 * sizeof(RGBQUAD); + } + g_bmapinfo_ptr = (BITMAPINFO *)GlobalAlloc(GPTR, + sizeof(BITMAPINFOHEADER) + extra_size); + + g_bmaphdr_ptr = (BITMAPINFOHEADER *)g_bmapinfo_ptr; + g_bmaphdr_ptr->biSize = sizeof(BITMAPINFOHEADER); + g_bmaphdr_ptr->biWidth = A2_WINDOW_WIDTH; + g_bmaphdr_ptr->biHeight = -A2_WINDOW_HEIGHT; + g_bmaphdr_ptr->biPlanes = 1; + g_bmaphdr_ptr->biBitCount = g_screen_mdepth; + g_bmaphdr_ptr->biCompression = BI_RGB; + g_bmaphdr_ptr->biClrUsed = 0; + + video_get_kimages(); + + if(g_screen_depth != 8) { + // Allocate g_mainwin_kimage + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, + g_screen_mdepth); + } + + for(i = 0; i < 256; i++) { + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + + g_installed_full_superhires_colormap = 1; + + ShowWindow(g_hwnd_main, SW_SHOWDEFAULT); + UpdateWindow(g_hwnd_main); + + printf("Done with dev_video_init\n"); + fflush(stdout); + +} + +void +x_redraw_status_lines() +{ + COLORREF oldtextcolor, oldbkcolor; + char *buf; + int line; + int len; + int height; + int margin; + + height = 16; + margin = 0; + + oldtextcolor = SetTextColor(g_main_dc, 0); + oldbkcolor = SetBkColor(g_main_dc, 0xffffff); + for(line = 0; line < MAX_STATUS_LINES; line++) { + buf = g_status_ptrs[line]; + if(buf != 0) { + len = strlen(buf); + TextOut(g_main_dc, 10, X_A2_WINDOW_HEIGHT + + height*line + margin, buf, len); + } + } + SetTextColor(g_main_dc, oldtextcolor); + SetBkColor(g_main_dc, oldbkcolor); +} + + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, + int width, int height) +{ + void *bitm_old; + POINT point; + + point.x = 0; + point.y = 0; + ClientToScreen(g_hwnd_main, &point); + bitm_old = SelectObject(g_main_cdc, kimage_ptr->dev_handle); + + BitBlt(g_main_dc, destx, desty, width, height, + g_main_cdc, srcx, srcy, SRCCOPY); + + SelectObject(g_main_cdc, bitm_old); +} + +void +x_push_done() +{ +} + +void +x_auto_repeat_on(int must) +{ +} + +void +x_auto_repeat_off(int must) +{ +} + +void +x_hide_pointer(int do_hide) +{ + if(do_hide) { + ShowCursor(0); + } else { + ShowCursor(1); + } +} diff --git a/src/winresource.h b/src/winresource.h new file mode 100644 index 0000000..64e56e3 --- /dev/null +++ b/src/winresource.h @@ -0,0 +1,42 @@ +//{{NO_DEPENDENCIES}} +// $Id: $ +// Microsoft Developer Studio generated include file. +// Used by win32.rc +// +#define IDD_ABOUT_DIALOG 101 +#define IDC_KEGS32 102 +#define IDR_TOOLBAR 103 +#define IDD_DLG_DISKCONF 104 +#define IDR_ACCEL 105 +#define ID_TOOLBAR 5000 +#define ID_STATUSBAR 5001 +#define IDC_EDIT_S5D1 10051 +#define IDC_EDIT_S5D2 10052 +#define IDC_EDIT_S6D1 10061 +#define IDC_EDIT_S6D2 10062 +#define IDC_EDIT_S7D1 10071 +#define IDC_EDIT_S7D2 10072 +#define IDC_BTN_S5D1 11051 +#define IDC_BTN_S5D2 11052 +#define IDC_BTN_S6D1 11061 +#define IDC_BTN_S6D2 11062 +#define IDC_BTN_S7D1 11071 +#define IDC_BTN_S7D2 11072 +#define ID_HELP_ABOUT 40001 +#define ID_FILE_EXIT 40002 +#define ID_FILE_DISK 40003 +#define ID_FILE_SENDRESET 40004 +#define ID_FILE_JOYSTICK 40005 +#define ID_FILE_DEBUGSTAT 40006 +#define ID_FILE_FULLSCREEN 40012 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40013 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/xdriver.c b/src/xdriver.c new file mode 100644 index 0000000..7e5f7be --- /dev/null +++ b/src/xdriver.c @@ -0,0 +1,1306 @@ +/************************************************************************/ +/* KEGS: Apple //gs Emulator */ +/* Copyright 2002 by Kent Dickey */ +/* */ +/* This code is covered by the GNU GPL */ +/* */ +/* The KEGS web page is kegs.sourceforge.net */ +/* You may contact the author at: kadickey@alumni.princeton.edu */ +/************************************************************************/ + +const char rcsid_xdriver_c[] = "@(#)$KmKId: xdriver.c,v 1.181 2004-03-23 17:25:25-05 kentd Exp $"; + +# if !defined(__CYGWIN__) && !defined(__POWERPC__) +/* No shared memory on Cygwin */ +# define X_SHARED_MEM +#endif /* CYGWIN */ + +#include +#include +#include +#include +#include +#include + +#ifdef X_SHARED_MEM +# include +# include +# include +#endif + +int XShmQueryExtension(Display *display); +void _XInitImageFuncPtrs(XImage *xim); + +#include "defc.h" +#include "protos_xdriver.h" + +#define FONT_NAME_STATUS "8x13" + +extern int Verbose; + +extern int g_warp_pointer; +extern int g_screen_depth; +extern int g_force_depth; +int g_screen_mdepth = 0; + +extern int _Xdebug; + +extern int g_send_sound_to_file; + +extern int g_quit_sim_now; + +int g_has_focus = 0; +int g_auto_repeat_on = -1; +int g_x_shift_control_state = 0; + + +Display *g_display = 0; +Visual *g_vis = 0; +Window g_a2_win; +GC g_a2_winGC; +XFontStruct *g_text_FontSt; +Colormap g_a2_colormap = 0; +Colormap g_default_colormap = 0; +int g_needs_cmap = 0; + +extern word32 g_red_mask; +extern word32 g_green_mask; +extern word32 g_blue_mask; +extern int g_red_left_shift; +extern int g_green_left_shift; +extern int g_blue_left_shift; +extern int g_red_right_shift; +extern int g_green_right_shift; +extern int g_blue_right_shift; + +#ifdef X_SHARED_MEM +int g_use_shmem = 1; +#else +int g_use_shmem = 0; +#endif + +extern Kimage g_mainwin_kimage; + +extern int Max_color_size; + +XColor g_xcolor_a2vid_array[256]; + +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; + +int g_alt_left_up = 1; +int g_alt_right_up = 1; + +extern word32 g_full_refresh_needed; + +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; + +extern int g_lores_colors[]; +extern int g_cur_a2_stat; + +extern int g_a2vid_palette; + +extern int g_installed_full_superhires_colormap; + +extern int g_screen_redraw_skip_amt; + +extern word32 g_a2_screen_buffer_changed; + +extern char *g_status_ptrs[MAX_STATUS_LINES]; + +Cursor g_cursor; +Pixmap g_cursor_shape; +Pixmap g_cursor_mask; + +XColor g_xcolor_black = { 0, 0x0000, 0x0000, 0x0000, DoRed|DoGreen|DoBlue, 0 }; +XColor g_xcolor_white = { 0, 0xffff, 0xffff, 0xffff, DoRed|DoGreen|DoBlue, 0 }; + +int g_depth_attempt_list[] = { 16, 24, 15, 8 }; + + +#define X_EVENT_LIST_ALL_WIN \ + (ExposureMask | ButtonPressMask | ButtonReleaseMask | \ + OwnerGrabButtonMask | KeyPressMask | KeyReleaseMask | \ + KeymapStateMask | ColormapChangeMask | FocusChangeMask) + +#define X_BASE_WIN_EVENT_LIST \ + (X_EVENT_LIST_ALL_WIN | PointerMotionMask | ButtonMotionMask) + +#define X_A2_WIN_EVENT_LIST \ + (X_BASE_WIN_EVENT_LIST) + +int g_num_a2_keycodes = 0; + +int a2_key_to_xsym[][3] = { + { 0x35, XK_Escape, 0 }, + { 0x7a, XK_F1, 0 }, + { 0x7b, XK_F2, 0 }, + { 0x63, XK_F3, 0 }, + { 0x76, XK_F4, 0 }, + { 0x60, XK_F5, 0 }, + { 0x61, XK_F6, 0 }, + { 0x62, XK_F7, 0 }, + { 0x64, XK_F8, 0 }, + { 0x65, XK_F9, 0 }, + { 0x6d, XK_F10, 0 }, + { 0x67, XK_F11, 0 }, + { 0x6f, XK_F12, 0 }, + { 0x69, XK_F13, 0 }, + { 0x6b, XK_F14, 0 }, + { 0x71, XK_F15, 0 }, + { 0x7f, XK_Pause, XK_Break }, + { 0x32, '`', '~' }, /* Key number 18? */ + { 0x12, '1', '!' }, + { 0x13, '2', '@' }, + { 0x14, '3', '#' }, + { 0x15, '4', '$' }, + { 0x17, '5', '%' }, + { 0x16, '6', '^' }, + { 0x1a, '7', '&' }, + { 0x1c, '8', '*' }, + { 0x19, '9', '(' }, + { 0x1d, '0', ')' }, + { 0x1b, '-', '_' }, + { 0x18, '=', '+' }, + { 0x33, XK_BackSpace, 0 }, + { 0x72, XK_Insert, 0 }, /* Help? */ +/* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ + { 0x74, XK_Page_Up, 0 }, + { 0x47, XK_Num_Lock, XK_Clear }, /* Clear */ + { 0x51, XK_KP_Equal, XK_Home }, /* Note XK_Home alias! */ + { 0x4b, XK_KP_Divide, 0 }, + { 0x43, XK_KP_Multiply, 0 }, + + { 0x30, XK_Tab, 0 }, + { 0x0c, 'q', 'Q' }, + { 0x0d, 'w', 'W' }, + { 0x0e, 'e', 'E' }, + { 0x0f, 'r', 'R' }, + { 0x11, 't', 'T' }, + { 0x10, 'y', 'Y' }, + { 0x20, 'u', 'U' }, + { 0x22, 'i', 'I' }, + { 0x1f, 'o', 'O' }, + { 0x23, 'p', 'P' }, + { 0x21, '[', '{' }, + { 0x1e, ']', '}' }, + { 0x2a, 0x5c, '|' }, /* backslash, bar */ + { 0x75, XK_Delete, 0 }, + { 0x77, XK_End, 0 }, + { 0x79, XK_Page_Down, 0 }, + { 0x59, XK_KP_7, XK_KP_Home }, + { 0x5b, XK_KP_8, XK_KP_Up }, + { 0x5c, XK_KP_9, XK_KP_Page_Up }, + { 0x4e, XK_KP_Subtract, 0 }, + + { 0x39, XK_Caps_Lock, 0 }, + { 0x00, 'a', 'A' }, + { 0x01, 's', 'S' }, + { 0x02, 'd', 'D' }, + { 0x03, 'f', 'F' }, + { 0x05, 'g', 'G' }, + { 0x04, 'h', 'H' }, + { 0x26, 'j', 'J' }, + { 0x28, 'k', 'K' }, + { 0x25, 'l', 'L' }, + { 0x29, ';', ':' }, + { 0x27, 0x27, '"' }, /* single quote */ + { 0x24, XK_Return, 0 }, + { 0x56, XK_KP_4, XK_KP_Left }, + { 0x57, XK_KP_5, 0 }, + { 0x58, XK_KP_6, XK_KP_Right }, + { 0x45, XK_KP_Add, 0 }, + + { 0x38, XK_Shift_L, XK_Shift_R }, + { 0x06, 'z', 'Z' }, + { 0x07, 'x', 'X' }, + { 0x08, 'c', 'C' }, + { 0x09, 'v', 'V' }, + { 0x0b, 'b', 'B' }, + { 0x2d, 'n', 'N' }, + { 0x2e, 'm', 'M' }, + { 0x2b, ',', '<' }, + { 0x2f, '.', '>' }, + { 0x2c, '/', '?' }, + { 0x3e, XK_Up, 0 }, + { 0x53, XK_KP_1, XK_KP_End }, + { 0x54, XK_KP_2, XK_KP_Down }, + { 0x55, XK_KP_3, XK_KP_Page_Down }, + + { 0x36, XK_Control_L, XK_Control_R }, + { 0x3a, XK_Print, XK_Sys_Req }, /* Option */ + { 0x37, XK_Scroll_Lock, 0 }, /* Command */ + { 0x31, ' ', 0 }, + { 0x3b, XK_Left, 0 }, + { 0x3d, XK_Down, 0 }, + { 0x3c, XK_Right, 0 }, + { 0x52, XK_KP_0, XK_KP_Insert }, + { 0x41, XK_KP_Decimal, XK_KP_Separator }, + { 0x4c, XK_KP_Enter, 0 }, + { -1, -1, -1 } +}; + +int +main(int argc, char **argv) +{ + return kegsmain(argc, argv); +} + + +#define MAKE_2(val) ( (val << 8) + val) + +void +x_update_color(int col_num, int red, int green, int blue, word32 rgb) +{ + XColor *xcol; + + xcol = &(g_xcolor_a2vid_array[col_num]); + xcol->red = MAKE_2(red); + xcol->green = MAKE_2(green); + xcol->blue = MAKE_2(blue); + xcol->flags = DoRed | DoGreen | DoBlue; +} + +void +x_update_physical_colormap() +{ + if(g_needs_cmap) { + XStoreColors(g_display, g_a2_colormap, + &g_xcolor_a2vid_array[0], Max_color_size); + } +} + +void +show_xcolor_array() +{ + int i; + + for(i = 0; i < 256; i++) { + printf("%02x: %08x\n", i, g_palette_8to1624[i]); + +#if 0 + printf("%02x: %04x %04x %04x, %02x %x\n", + i, xcolor_array[i].red, xcolor_array[i].green, + xcolor_array[i].blue, (word32)xcolor_array[i].pixel, + xcolor_array[i].flags); +#endif + } +} + + +int +my_error_handler(Display *display, XErrorEvent *ev) +{ + char msg[1024]; + XGetErrorText(display, ev->error_code, msg, 1000); + printf("X Error code %s\n", msg); + fflush(stdout); + + return 0; +} + +void +xdriver_end() +{ + + printf("xdriver_end\n"); + if(g_display) { + x_auto_repeat_on(1); + XFlush(g_display); + } +} + +void +show_colormap(char *str, Colormap cmap, int index1, int index2, int index3) +{ + XColor xcol; + int i; + int pix; + + printf("Show colormap: %08x = %s, cmap cells: %d,%d,%d\n", + (int)cmap, str, index1, index2, index3); + for(i = 0; i < index1 + index2 + index3; i++) { + pix = i; + if(i >= index1) { + pix = (i-index1)*index1; + if(i >= (index1 + index2)) { + pix = (i - index1 - index2)*index2*index1; + } + } + if(i == 0 && index1 < 250) { + pix = 0x842; + } + xcol.pixel = pix; + XQueryColor(g_display, cmap, &xcol); + printf("Cell %03x: pix: %03x, R:%04x, G:%04x, B:%04x\n", + i, (int)xcol.pixel, xcol.red, xcol.green, xcol.blue); + } +} + +void +x_badpipe(int signum) +{ + /* restore normal sigpipe handling */ + signal(SIGPIPE, SIG_DFL); + + /* attempt to xset r */ + system("xset r"); + my_exit(5); +} + +void +dev_video_init() +{ + int tmp_array[0x80]; + XGCValues new_gc; + XSetWindowAttributes win_attr; + XSizeHints my_winSizeHints; + XClassHint my_winClassHint; + XTextProperty my_winText; + XVisualInfo *visualList; + char **font_ptr; + char cursor_data; + word32 create_win_list; + int depth; + int len; + int cmap_alloc_amt; + int cnt; + int font_height; + int base_height; + int screen_num; + char *myTextString[1]; + word32 lores_col; + int ret; + int i; + int keycode; + + printf("Preparing X Windows graphics system\n"); + ret = 0; + + signal(SIGPIPE, x_badpipe); + + g_num_a2_keycodes = 0; + for(i = 0; i <= 0x7f; i++) { + tmp_array[i] = 0; + } + for(i = 0; i < 0x7f; i++) { + keycode = a2_key_to_xsym[i][0]; + if(keycode < 0) { + g_num_a2_keycodes = i; + break; + } else if(keycode > 0x7f) { + printf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); + exit(2); + } else { + if(tmp_array[keycode]) { + printf("a2_key_to_x[%d] = %02x used by %d\n", + i, keycode, tmp_array[keycode] - 1); + } + tmp_array[keycode] = i + 1; + } + } + +#if 0 + printf("Setting _Xdebug = 1, makes X synchronous\n"); + _Xdebug = 1; +#endif + + g_display = XOpenDisplay(NULL); + if(g_display == NULL) { + fprintf(stderr, "Can't open display\n"); + exit(1); + } + + vid_printf("Just opened display = %p\n", g_display); + fflush(stdout); + + screen_num = DefaultScreen(g_display); + + len = sizeof(g_depth_attempt_list)/sizeof(int); + if(g_force_depth > 0) { + /* Only use the requested user depth */ + len = 1; + g_depth_attempt_list[0] = g_force_depth; + } + g_vis = 0; + for(i = 0; i < len; i++) { + depth = g_depth_attempt_list[i]; + + g_vis = x_try_find_visual(depth, screen_num, + &visualList); + if(g_vis != 0) { + break; + } + } + if(g_vis == 0) { + fprintf(stderr, "Couldn't find any visuals at any depth!\n"); + exit(2); + } + + g_default_colormap = XDefaultColormap(g_display, screen_num); + if(!g_default_colormap) { + printf("g_default_colormap == 0!\n"); + exit(4); + } + + g_a2_colormap = -1; + cmap_alloc_amt = AllocNone; + if(g_needs_cmap) { + cmap_alloc_amt = AllocAll; + } + g_a2_colormap = XCreateColormap(g_display, + RootWindow(g_display,screen_num), g_vis, + cmap_alloc_amt); + + vid_printf("g_a2_colormap: %08x, main: %08x\n", + (word32)g_a2_colormap, (word32)g_default_colormap); + + if(g_needs_cmap && g_a2_colormap == g_default_colormap) { + printf("A2_colormap = default colormap!\n"); + exit(4); + } + + /* and define cursor */ + cursor_data = 0; + g_cursor_shape = XCreatePixmapFromBitmapData(g_display, + RootWindow(g_display,screen_num), &cursor_data, 1, 1, 1, 0, 1); + g_cursor_mask = XCreatePixmapFromBitmapData(g_display, + RootWindow(g_display,screen_num), &cursor_data, 1, 1, 1, 0, 1); + + g_cursor = XCreatePixmapCursor(g_display, g_cursor_shape, + g_cursor_mask, &g_xcolor_black, &g_xcolor_white, 0, 0); + + XFreePixmap(g_display, g_cursor_shape); + XFreePixmap(g_display, g_cursor_mask); + + XFlush(g_display); + + win_attr.event_mask = X_A2_WIN_EVENT_LIST; + win_attr.colormap = g_a2_colormap; + win_attr.backing_store = WhenMapped; + win_attr.border_pixel = 1; + win_attr.background_pixel = 0; + if(g_warp_pointer) { + win_attr.cursor = g_cursor; + } else { + win_attr.cursor = None; + } + + vid_printf("About to a2_win, depth: %d\n", g_screen_depth); + fflush(stdout); + + create_win_list = CWEventMask | CWBackingStore | CWCursor; + create_win_list |= CWColormap | CWBorderPixel | CWBackPixel; + + base_height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES * 13); + + g_a2_win = XCreateWindow(g_display, RootWindow(g_display, screen_num), + 0, 0, BASE_WINDOW_WIDTH, base_height, + 0, g_screen_depth, InputOutput, g_vis, + create_win_list, &win_attr); + + XSetWindowColormap(g_display, g_a2_win, g_a2_colormap); + + XFlush(g_display); + +/* Check for XShm */ +#ifdef X_SHARED_MEM + if(g_use_shmem) { + ret = XShmQueryExtension(g_display); + if(ret == 0) { + printf("XShmQueryExt ret: %d\n", ret); + printf("not using shared memory\n"); + g_use_shmem = 0; + } else { + printf("Will use shared memory for X\n"); + } + } +#endif + + video_get_kimages(); + if(g_screen_depth != 8) { + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, + g_screen_mdepth); + } + + if(!g_use_shmem) { + if(g_screen_redraw_skip_amt < 0) { + g_screen_redraw_skip_amt = 3; + } + printf("Not using shared memory, setting skip_amt = %d\n", + g_screen_redraw_skip_amt); + } + + /* Done with visualList now */ + XFree(visualList); + + for(i = 0; i < 256; i++) { + g_xcolor_a2vid_array[i].pixel = i; + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + + x_update_physical_colormap(); + + g_installed_full_superhires_colormap = !g_needs_cmap; + + myTextString[0] = "KEGS"; + + XStringListToTextProperty(myTextString, 1, &my_winText); + + my_winSizeHints.flags = PSize | PMinSize | PMaxSize; + my_winSizeHints.width = BASE_WINDOW_WIDTH; + my_winSizeHints.height = base_height; + my_winSizeHints.min_width = BASE_WINDOW_WIDTH; + my_winSizeHints.min_height = base_height; + my_winSizeHints.max_width = BASE_WINDOW_WIDTH; + my_winSizeHints.max_height = base_height; + my_winClassHint.res_name = "KEGS"; + my_winClassHint.res_class = "KEGS"; + + XSetWMProperties(g_display, g_a2_win, &my_winText, &my_winText, 0, + 0, &my_winSizeHints, 0, &my_winClassHint); + XMapRaised(g_display, g_a2_win); + + XSync(g_display, False); + + g_a2_winGC = XCreateGC(g_display, g_a2_win, 0, (XGCValues *) 0); + font_ptr = XListFonts(g_display, FONT_NAME_STATUS, 4, &cnt); + + vid_printf("act_cnt of fonts: %d\n", cnt); + for(i = 0; i < cnt; i++) { + vid_printf("Font %d: %s\n", i, font_ptr[i]); + } + fflush(stdout); + g_text_FontSt = XLoadQueryFont(g_display, FONT_NAME_STATUS); + vid_printf("font # returned: %08x\n", (word32)(g_text_FontSt->fid)); + font_height = g_text_FontSt->ascent + g_text_FontSt->descent; + vid_printf("font_height: %d\n", font_height); + + vid_printf("widest width: %d\n", g_text_FontSt->max_bounds.width); + + new_gc.font = g_text_FontSt->fid; + new_gc.fill_style = FillSolid; + XChangeGC(g_display, g_a2_winGC, GCFillStyle | GCFont, &new_gc); + + /* XSync(g_display, False); */ +#if 0 +/* MkLinux for Powermac depth 15 has bugs--this was to try to debug them */ + if(g_screen_depth == 15) { + /* draw phony screen */ + ptr16 = (word16 *)dint_main_win; + for(i = 0; i < 320*400; i++) { + ptr16[i] = 0; + } + for(i = 0; i < 400; i++) { + for(j = 0; j < 640; j++) { + sh = (j / 20) & 0x1f; + val = sh; + val = val; + *ptr16++ = val; + } + } + XPutImage(g_display, g_a2_win, g_a2_winGC, xint_main_win, + 0, 0, + BASE_MARGIN_LEFT, BASE_MARGIN_TOP, + 640, 400); + XFlush(g_display); + } +#endif + + + XFlush(g_display); + fflush(stdout); +} + +Visual * +x_try_find_visual(int depth, int screen_num, XVisualInfo **visual_list_ptr) +{ + XVisualInfo *visualList; + XVisualInfo *v_chosen; + XVisualInfo vTemplate; + int visualsMatched; + int mdepth; + int needs_cmap; + int visual_chosen; + int match8, match24; + int i; + + vTemplate.screen = screen_num; + vTemplate.depth = depth; + + visualList = XGetVisualInfo(g_display, + (VisualScreenMask | VisualDepthMask), + &vTemplate, &visualsMatched); + + vid_printf("visuals matched: %d\n", visualsMatched); + if(visualsMatched == 0) { + return (Visual *)0; + } + + visual_chosen = -1; + needs_cmap = 0; + for(i = 0; i < visualsMatched; i++) { + printf("Visual %d\n", i); + printf(" id: %08x, screen: %d, depth: %d, class: %d\n", + (word32)visualList[i].visualid, + visualList[i].screen, + visualList[i].depth, + visualList[i].class); + printf(" red: %08lx, green: %08lx, blue: %08lx\n", + visualList[i].red_mask, + visualList[i].green_mask, + visualList[i].blue_mask); + printf(" cmap size: %d, bits_per_rgb: %d\n", + visualList[i].colormap_size, + visualList[i].bits_per_rgb); + match8 = (visualList[i].class == PseudoColor); + match24 = (visualList[i].class == TrueColor); + if((depth == 8) && match8) { + visual_chosen = i; + Max_color_size = visualList[i].colormap_size; + needs_cmap = 1; + break; + } + if((depth != 8) && match24) { + visual_chosen = i; + Max_color_size = -1; + needs_cmap = 0; + break; + } + } + + if(visual_chosen < 0) { + printf("Couldn't find any good visuals at depth %d!\n", + depth); + return (Visual *)0; + } + + printf("Chose visual: %d, max_colors: %d\n", visual_chosen, + Max_color_size); + + v_chosen = &(visualList[visual_chosen]); + x_set_mask_and_shift(v_chosen->red_mask, &g_red_mask, + &g_red_left_shift, &g_red_right_shift); + x_set_mask_and_shift(v_chosen->green_mask, &g_green_mask, + &g_green_left_shift, &g_green_right_shift); + x_set_mask_and_shift(v_chosen->blue_mask, &g_blue_mask, + &g_blue_left_shift, &g_blue_right_shift); + + g_screen_depth = depth; + mdepth = depth; + if(depth > 8) { + mdepth = 16; + } + if(depth > 16) { + mdepth = 32; + } + g_screen_mdepth = mdepth; + g_needs_cmap = needs_cmap; + *visual_list_ptr = visualList; + + return v_chosen->visual; +} + +void +x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, + int *shift_right_ptr) +{ + int shift; + int i; + + /* Shift until we find first set bit in mask, then remember mask,shift*/ + + shift = 0; + for(i = 0; i < 32; i++) { + if(x_mask & 1) { + /* we're done! */ + break; + } + x_mask = x_mask >> 1; + shift++; + } + *mask_ptr = x_mask; + *shift_left_ptr = shift; + /* Now, calculate shift_right_ptr */ + shift = 0; + x_mask |= 1; // make sure at least one bit is set + while(x_mask < 0x80) { + shift++; + x_mask = x_mask << 1; + } + + *shift_right_ptr = shift; + return; + +} + +int g_xshm_error = 0; + +int +xhandle_shm_error(Display *display, XErrorEvent *event) +{ + g_xshm_error = 1; + return 0; +} + +void +x_get_kimage(Kimage *kimage_ptr) { + if(g_use_shmem) { + g_use_shmem = get_shm(kimage_ptr); + } + if(!g_use_shmem) { + get_ximage(kimage_ptr); + } +} + +int +get_shm(Kimage *kimage_ptr) +{ +#ifdef X_SHARED_MEM + XShmSegmentInfo *seginfo; + XImage *xim; + int (*old_x_handler)(Display *, XErrorEvent *); + int width; + int height; + int depth; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + + seginfo = (XShmSegmentInfo *)malloc(sizeof(XShmSegmentInfo)); + xim = XShmCreateImage(g_display, g_vis, depth, ZPixmap, + (char *)0, seginfo, width, height); + + /* check mdepth! */ + if(xim->bits_per_pixel != kimage_ptr->mdepth) { + printf("get_shm bits_per_pix: %d != %d\n", + xim->bits_per_pixel, g_screen_mdepth); + } + + vid_printf("xim: %p\n", xim); + kimage_ptr->dev_handle = xim; + kimage_ptr->dev_handle2 = seginfo; + if(xim == 0) { + return 0; + } + + /* It worked, we got it */ + seginfo->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, + IPC_CREAT | 0777); + vid_printf("seginfo->shmid = %d\n", seginfo->shmid); + if(seginfo->shmid < 0) { + XDestroyImage(xim); + return 0; + } + + /* Still working */ + seginfo->shmaddr = (char *)shmat(seginfo->shmid, 0, 0); + vid_printf("seginfo->shmaddr: %p\n", seginfo->shmaddr); + if(seginfo->shmaddr == ((char *) -1)) { + XDestroyImage(xim); + return 0; + } + + /* Still working */ + xim->data = seginfo->shmaddr; + seginfo->readOnly = False; + + /* XShmAttach will trigger X error if server is remote, so catch it */ + g_xshm_error = 0; + old_x_handler = XSetErrorHandler(xhandle_shm_error); + + XShmAttach(g_display, seginfo); + XSync(g_display, False); + + + vid_printf("about to RMID the shmid\n"); + shmctl(seginfo->shmid, IPC_RMID, 0); + + XFlush(g_display); + XSetErrorHandler(old_x_handler); + + if(g_xshm_error) { + XDestroyImage(xim); + /* We could release the shared mem segment, but by doing the */ + /* RMID, it will go away when we die now, so just leave it */ + printf("Not using shared memory\n"); + return 0; + } + + kimage_ptr->data_ptr = (byte *)xim->data; + vid_printf("Sharing memory. xim: %p, xim->data: %p\n", xim, xim->data); + + return 1; +#else + return 0; /* No shared memory */ +#endif /* X_SHARED_MEM */ +} + +void +get_ximage(Kimage *kimage_ptr) +{ + XImage *xim; + byte *ptr; + int width; + int height; + int depth; + int mdepth; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + mdepth = kimage_ptr->mdepth; + + ptr = (byte *)malloc((width * height * mdepth) >> 3); + + vid_printf("ptr: %p\n", ptr); + + if(ptr == 0) { + printf("malloc for data failed, mdepth: %d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + xim = XCreateImage(g_display, g_vis, depth, ZPixmap, 0, + (char *)ptr, width, height, 8, 0); + +#ifdef KEGS_LITTLE_ENDIAN + xim->byte_order = LSBFirst; +#else + xim->byte_order = MSBFirst; +#endif + _XInitImageFuncPtrs(xim); /* adjust to new byte order */ + + /* check mdepth! */ + if(xim->bits_per_pixel != mdepth) { + printf("shm_ximage bits_per_pix: %d != %d\n", + xim->bits_per_pixel, mdepth); + } + + vid_printf("xim: %p\n", xim); + + kimage_ptr->dev_handle = xim; + + return; +} + + +void +x_redraw_status_lines() +{ + char *buf; + int line; + int height; + int margin; + word32 white, black; + + height = g_text_FontSt->ascent + g_text_FontSt->descent; + margin = g_text_FontSt->ascent; + + white = (g_a2vid_palette << 4) + 0xf; + black = (g_a2vid_palette << 4) + 0x0; + if(g_screen_depth != 8) { + white = (2 << (g_screen_depth - 1)) - 1; + black = 0; + } + XSetForeground(g_display, g_a2_winGC, white); + XSetBackground(g_display, g_a2_winGC, black); + + for(line = 0; line < MAX_STATUS_LINES; line++) { + buf = g_status_ptrs[line]; + if(buf == 0) { + /* skip it */ + continue; + } + XDrawImageString(g_display, g_a2_win, g_a2_winGC, 0, + X_A2_WINDOW_HEIGHT + height*line + margin, + buf, strlen(buf)); + } + + XFlush(g_display); +} + + + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, + int width, int height) +{ + XImage *xim; + + xim = (XImage *)kimage_ptr->dev_handle; + +#ifdef X_SHARED_MEM + if(g_use_shmem) { + XShmPutImage(g_display, g_a2_win, g_a2_winGC, xim, + srcx, srcy, destx, desty, width, height, False); + } +#endif + if(!g_use_shmem) { + XPutImage(g_display, g_a2_win, g_a2_winGC, xim, + srcx, srcy, destx, desty, width, height); + } +} + +void +x_push_done() +{ + XFlush(g_display); +} + + +#define KEYBUFLEN 128 + +int g_num_check_input_calls = 0; +int g_check_input_flush_rate = 2; + +int +x_update_mouse(int raw_x, int raw_y, int button_states, int buttons_valid) +{ + int x, y; + + x = raw_x - BASE_MARGIN_LEFT; + y = raw_y - BASE_MARGIN_TOP; + + if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && + (y == A2_WINDOW_HEIGHT/2) && (buttons_valid == 0) ) { + /* tell adb routs to recenter but ignore this motion */ + update_mouse(x, y, 0, -1); + return 0; + } + return update_mouse(x, y, button_states, buttons_valid & 7); +} + +void +check_input_events() +{ + XEvent ev; + int len; + int motion; + int buttons; + int refresh_needed; + + g_num_check_input_calls--; + if(g_num_check_input_calls < 0) { + len = XPending(g_display); + g_num_check_input_calls = g_check_input_flush_rate; + } else { + len = QLength(g_display); + } + + motion = 0; + refresh_needed = 0; + while(len > 0) { + XNextEvent(g_display, &ev); + len--; + if(len == 0) { + /* Xaccel on linux only buffers one X event */ + /* must look for more now */ + len = XPending(g_display); + } + switch(ev.type) { + case FocusIn: + case FocusOut: + if(ev.xfocus.type == FocusOut) { + /* Allow keyrepeat again! */ + vid_printf("Left window, auto repeat on\n"); + x_auto_repeat_on(0); + g_has_focus = 0; + } else if(ev.xfocus.type == FocusIn) { + /* Allow keyrepeat again! */ + vid_printf("Enter window, auto repeat off\n"); + x_auto_repeat_off(0); + g_has_focus = 1; + } + break; + case EnterNotify: + case LeaveNotify: + /* These events are disabled now */ + printf("Enter/Leave event for winow %08x, sub: %08x\n", + (word32)ev.xcrossing.window, + (word32)ev.xcrossing.subwindow); + printf("Enter/L mode: %08x, detail: %08x, type:%02x\n", + ev.xcrossing.mode, ev.xcrossing.detail, + ev.xcrossing.type); + break; + case ButtonPress: + vid_printf("Got button press of button %d!\n", + ev.xbutton.button); + buttons = (1 << ev.xbutton.button) >> 1; + motion |= x_update_mouse(ev.xbutton.x, ev.xbutton.y, + buttons, buttons & 7); + + break; + case ButtonRelease: + buttons = (1 << ev.xbutton.button) >> 1; + motion |= x_update_mouse(ev.xbutton.x, ev.xbutton.y, 0, + buttons & 7); + break; + case MotionNotify: + if(ev.xmotion.window != g_a2_win) { + printf("Motion in window %08x unknown!\n", + (word32)ev.xmotion.window); + } + motion |= x_update_mouse(ev.xmotion.x, ev.xmotion.y, 0, + 0); + break; + case Expose: + refresh_needed = -1; + break; + case NoExpose: + /* do nothing */ + break; + case KeyPress: + case KeyRelease: + handle_keysym(&ev); + break; + case KeymapNotify: + break; + case ColormapNotify: + vid_printf("ColormapNotify for %08x\n", + (word32)(ev.xcolormap.window)); + vid_printf("colormap: %08x, new: %d, state: %d\n", + (word32)ev.xcolormap.colormap, + ev.xcolormap.new, ev.xcolormap.state); + break; + default: + printf("X event 0x%08x is unknown!\n", + ev.type); + break; + } + } + + if(motion && g_warp_pointer) { + XWarpPointer(g_display, None, g_a2_win, 0, 0, 0, 0, + BASE_MARGIN_LEFT + (A2_WINDOW_WIDTH/2), + BASE_MARGIN_TOP + (A2_WINDOW_HEIGHT/2)); + } + + if(refresh_needed) { + printf("Full refresh needed\n"); + g_a2_screen_buffer_changed = -1; + g_full_refresh_needed = -1; + + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_status_refresh_needed = 1; + + /* x_refresh_ximage(); */ + /* redraw_border(); */ + } + +} + +void +x_hide_pointer(int do_hide) +{ + if(do_hide) { + XDefineCursor(g_display, g_a2_win, g_cursor); + } else { + XDefineCursor(g_display, g_a2_win, None); + } +} + + +void +handle_keysym(XEvent *xev_in) +{ + KeySym keysym; + word32 state; + int keycode; + int a2code; + int type; + int is_up; + + keycode = xev_in->xkey.keycode; + type = xev_in->xkey.type; + + keysym = XLookupKeysym(&(xev_in->xkey), 0); + + state = xev_in->xkey.state; + + vid_printf("keycode: %d, type: %d, state:%d, sym: %08x\n", + keycode, type, state, (word32)keysym); + + x_update_modifier_state(state); + + is_up = 0; + if(type == KeyRelease) { + is_up = 1; + } + +#if 0 + if(keysym == XK_Alt_L || keysym == XK_Meta_L) { + g_alt_left_up = is_up; + } + + if(keysym == XK_Alt_R || keysym == XK_Meta_R) { + g_alt_right_up = is_up; + } + + if(g_alt_left_up == 0 && g_alt_right_up == 0) { + printf("Sending sound to file\n"); + g_send_sound_to_file = 1; + } else { + if(g_send_sound_to_file) { + printf("Stopping sending sound to file\n"); + close_sound_file(); + } + g_send_sound_to_file = 0; + } +#endif + + /* first, do conversions */ + switch(keysym) { + case XK_Alt_R: + case XK_Meta_R: + case XK_Mode_switch: + case XK_Cancel: + keysym = XK_Print; /* option */ + break; + case XK_Alt_L: + case XK_Meta_L: + case XK_Menu: + keysym = XK_Scroll_Lock; /* cmd */ + break; + case NoSymbol: + switch(keycode) { + /* 94-95 are for my PC101 kbd + windows keys on HPUX */ + case 0x0095: + /* left windows key = option */ + keysym = XK_Print; + break; + case 0x0096: + case 0x0094: + /* right windows key = cmd */ + keysym = XK_Scroll_Lock; + break; + /* 0072 is for cra@WPI.EDU who says it's Break under XFree86 */ + case 0x0072: + /* 006e is break according to mic@research.nj.nec.com */ + case 0x006e: + keysym = XK_Break; + break; + + /* 0x0042, 0x0046, and 0x0048 are the windows keys according */ + /* to Geoff Weiss on Solaris x86 */ + case 0x0042: + case 0x0046: + /* flying windows == open apple */ + keysym = XK_Scroll_Lock; + break; + case 0x0048: + /* menu windows == option */ + keysym = XK_Print; + break; + } + } + + a2code = x_keysym_to_a2code(keysym, is_up); + if(a2code >= 0) { + adb_physical_key_update(a2code, is_up); + } else if(a2code != -2) { + printf("Keysym: %04x of keycode: %02x unknown\n", + (word32)keysym, keycode); + } +} + +int +x_keysym_to_a2code(int keysym, int is_up) +{ + int i; + + if(keysym == 0) { + return -1; + } + + if((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) { + if(is_up) { + g_x_shift_control_state &= ~ShiftMask; + } else { + g_x_shift_control_state |= ShiftMask; + } + } + if(keysym == XK_Caps_Lock) { + if(is_up) { + g_x_shift_control_state &= ~LockMask; + } else { + g_x_shift_control_state |= LockMask; + } + } + if((keysym == XK_Control_L) || (keysym == XK_Control_R)) { + if(is_up) { + g_x_shift_control_state &= ~ControlMask; + } else { + g_x_shift_control_state |= ControlMask; + } + } + + /* Look up Apple 2 keycode */ + for(i = g_num_a2_keycodes - 1; i >= 0; i--) { + if((keysym == a2_key_to_xsym[i][1]) || + (keysym == a2_key_to_xsym[i][2])) { + + vid_printf("Found keysym:%04x = a[%d] = %04x or %04x\n", + (int)keysym, i, a2_key_to_xsym[i][1], + a2_key_to_xsym[i][2]); + + return a2_key_to_xsym[i][0]; + } + } + + return -1; +} + +void +x_update_modifier_state(int state) +{ + int state_xor; + int is_up; + + state = state & (ControlMask | LockMask | ShiftMask); + state_xor = g_x_shift_control_state ^ state; + is_up = 0; + if(state_xor & ControlMask) { + is_up = ((state & ControlMask) == 0); + adb_physical_key_update(0x36, is_up); + } + if(state_xor & LockMask) { + is_up = ((state & LockMask) == 0); + adb_physical_key_update(0x39, is_up); + } + if(state_xor & ShiftMask) { + is_up = ((state & ShiftMask) == 0); + adb_physical_key_update(0x38, is_up); + } + + g_x_shift_control_state = state; +} + +void +x_auto_repeat_on(int must) +{ + if((g_auto_repeat_on <= 0) || must) { + g_auto_repeat_on = 1; + XAutoRepeatOn(g_display); + XFlush(g_display); + adb_kbd_repeat_off(); + } +} + +void +x_auto_repeat_off(int must) +{ + if((g_auto_repeat_on != 0) || must) { + XAutoRepeatOff(g_display); + XFlush(g_display); + g_auto_repeat_on = 0; + adb_kbd_repeat_off(); + } +}