178 Commits

Author SHA1 Message Date
Aaron Culliney
27a848f61b Android 2.0.0 RC2 2018-11-25 16:26:58 -08:00
Aaron Culliney
253a99ead2 Ensure tests pass again 2018-11-25 16:19:56 -08:00
Aaron Culliney
b08c5d9289 Silence a firing assert for now 2018-11-25 15:32:24 -08:00
Aaron Culliney
5230afa788 Useability tweak for Millenials and kids ... disk images should be "inserted" read/write by default ;) 2018-11-25 14:45:39 -08:00
Aaron Culliney
1d2f521e0b Fix graphics tearing and stuttering for disk images that sync to video scanner
- Use a second framebuffer to avoid tearing
    - Occasionally stall graphics thread for ~4ms until CPU thread (video scanner) completes drawing a frame
    - These fixes seem to essentially fix graphics issues with Dagen Brock's Flappie Bird (flapple140.po.gz disk image)
2018-11-24 15:16:38 -08:00
Aaron Culliney
db4a71ca6f Enable Chromium systrace for all platforms 2018-11-24 15:15:34 -08:00
Aaron Culliney
27c45834d2 Rename systrace sources 2018-11-23 07:40:37 -08:00
Aaron Culliney
1e2449cfdf Misc Droid updates 2018-11-22 12:08:58 -08:00
Aaron Culliney
3317a23563 Correctly set video preferences 2018-11-22 10:36:28 -08:00
Aaron Culliney
346d7128d8 Fix some issues around disk loading preferences on macOS 2018-11-22 10:14:46 -08:00
Aaron Culliney
0478afe60e Pervasively use full range of signed 16bit samples for speaker 2018-11-22 10:10:24 -08:00
Aaron Culliney
d8e6f54c6b Update README.md 2018-11-21 13:02:21 -08:00
Aaron Culliney
e31a50a7fd Fix a few visual glitches in a hackish way because Android APIs are so damn atrocious 2018-11-20 13:20:06 -08:00
Aaron Culliney
e9ad630996 Android 2.0.0 RC1
- Completely new video scanner
    - NTSC video modes
    - Fast disk loading
2018-11-20 12:36:12 -08:00
Aaron Culliney
d3432fb3d8 Show release notes on first launch/upgrade
- Include a menu item to re-show the release notes
    - Upgrade migration sets new Color TV video mode
2018-11-20 12:34:34 -08:00
Aaron Culliney
3a35404fa3 Enable semi-hackish codepath to reduce audio glitching on fast loading 2018-11-20 12:08:37 -08:00
Aaron Culliney
ab0c796249 Do not go to max speed if no disk image "inserted" 2018-11-20 11:32:28 -08:00
Aaron Culliney
1d089af199 Default enable half scanlines because ... nostalgia :) 2018-11-20 11:31:43 -08:00
Aaron Culliney
6a519b7b5f Tests appear to be working on Droid 2018-11-20 11:30:18 -08:00
Aaron Culliney
8a347630b3 Changes insisted upon by Android Studio 2018-11-18 14:30:17 -08:00
Aaron Culliney
d890cddfa1 Better commentary for new settings 2018-11-18 14:28:54 -08:00
Aaron Culliney
6f03b89283 Misc macOS tweaks 2018-11-18 14:27:17 -08:00
Aaron Culliney
fdc5bd33f0 Fix occasional scanner glitching 2018-11-18 14:24:31 -08:00
Aaron Culliney
aef25292b7 Fix occasional scanner glitching 2018-11-18 13:08:22 -08:00
Aaron Culliney
8b19ba762f Render up to 7 extra scanlines to redraw entire text row when video frame is dirty
- Appears to fix occasional underdraw of bottom row cursor when in 80 column text mode
2018-11-18 12:05:49 -08:00
Aaron Culliney
184884635b Fix compiler warnings in Droid build 2018-11-17 15:57:27 -08:00
Aaron Culliney
92369c3fdb Fix some compiler warnings and tests pass on desktop Linux 2018-11-17 15:52:51 -08:00
Aaron Culliney
0625084602 Avoid deadlock in log rotation 2018-11-17 15:52:14 -08:00
Aaron Culliney
05633d4b0e Unbreak Desktop Linux build 2018-11-17 13:35:35 -08:00
Aaron Culliney
55418504f4 Fix testing after recent video scanner upheaval 2018-11-17 12:39:43 -08:00
Aaron Culliney
8e3c07ed57 Fix some broken preference handling 2018-11-17 11:14:11 -08:00
Aaron Culliney
05d3d884b9 Fix testdisplay after video scanner upheaval 2018-11-17 10:39:28 -08:00
Aaron Culliney
fb44420713 Testing is beginning to work again after upheaval
- testcpu, testvm, testdisk all look good
    - TODO : testdisplay, etc ...
2018-11-11 19:43:49 -08:00
Aaron Culliney
0ddd9ffd91 Use CONFORMANT_TRACKS for macOS build and re-arrange preprocessor macros 2018-11-11 13:18:52 -08:00
Aaron Culliney
80f741f225 Ensure correct pixel adjustment to framebuffer (over)-draw
- Ensures correct starting position for all modes
    - Renders the last 4 samples into the right side overdraw of framebuffer for NTSC modes
2018-11-11 12:17:23 -08:00
Aaron Culliney
aabc29e924 Refresh video after CPU pause
- Fixes rendering if new video mode selected
2018-11-11 12:10:33 -08:00
Aaron Culliney
32d5d2ee1c Avoid a memcpy in graphics pipeline 2018-11-11 08:22:49 -08:00
Aaron Culliney
f235dd6d7c Introduce some one-off memory fixes for poorly-written kracks 2018-11-11 08:22:04 -08:00
Aaron Culliney
ae5a2c4d61 Allow selection of disk images with wrong case extension 2018-11-11 07:30:35 -08:00
Aaron Culliney
dfbc97d7a5 Screen holes should not trigger graphics updates 2018-11-11 07:23:47 -08:00
Aaron Culliney
2928556be8 Optimize video scanner+generator when nothing has been drawn
- Video updates trigger one full frame + one (sub-)scanline re-generate
    - Otherwise video_scannerUpdate() doesn't do much work
2018-11-10 16:49:55 -08:00
Aaron Culliney
fa2f8569f8 Brighter half-scanlines and commentary 2018-11-10 10:28:53 -08:00
Aaron Culliney
a0f2819a4e Misc display fixes 2018-11-10 10:27:05 -08:00
Aaron Culliney
ed37c18ec5 Eliminate branch conditionals in scanner address calculation 2018-11-10 10:26:11 -08:00
Aaron Culliney
18d831b04c Fast disk loading is enabled from a pref 2018-11-07 06:49:16 -08:00
Aaron Culliney
227098ec52 Refactor video/display rendering
- Import NTSC video display modes
    - Migrate to using full-color framebuffers
    - Mac and Android builds somewhat working
    - TODO : likely breaks display testing
2018-11-04 14:07:30 -08:00
Aaron Culliney
8757cb2a06 Name some new prefs 2018-11-04 14:06:59 -08:00
Aaron Culliney
2a7e375f26 Minor refactor joystick prefs 2018-11-04 14:06:38 -08:00
Aaron Culliney
d443f01af3 Bugfix disk6_ioWrite 2018-10-13 07:38:05 -07:00
Aaron Culliney
50d440df1b Fix interpolated color after recent upheaval 2018-08-24 17:41:44 -07:00
Aaron Culliney
9f1ef968ac Improve display testing
- Also test graphics modes in COLOR_MODE_BW
    - Changed TESTHIRES80_2 to merge the two portions of the HIRES80 picture data
    - New TESTLORES_2 and TESTLORES80_2 that draws colors/patterns that better showcase continuous pixel data
2018-08-11 16:32:13 -07:00
Aaron Culliney
6ee8699079 Rename color_mode_t values for clarity 2018-08-11 15:54:00 -07:00
Aaron Culliney
0f3ba15e87 Fix build break on touch devices 2018-08-07 07:57:51 -07:00
Aaron Culliney
5b3d0799a3 Upgrade to newer Android Studio and build tools
- Target Oreo per Goog's dictat
    - Min SDK is now 14 (ICS - 4.0) per build tools requirement
2018-08-07 07:55:59 -07:00
Aaron Culliney
530aaa4f77 Clean up included sample disks 2018-08-07 07:51:31 -07:00
Aaron Culliney
3183dd20b7 Added second LORES80 test screen 2018-08-05 17:25:43 -07:00
Aaron Culliney
55ca51262b First cut at monochrome for LORES80 2018-08-05 17:19:15 -07:00
Aaron Culliney
b403ee7b6e Fix LORES80 shifting algorithm
- Previous variant was not properly truncating bit 9
2018-08-05 17:18:48 -07:00
Aaron Culliney
58488ab8e9 Remove a conditional codepath in LORES40 drawing 2018-08-05 16:00:53 -07:00
Aaron Culliney
0f38791940 Improve a flappy display test 2018-07-29 19:58:59 -07:00
Aaron Culliney
dc49060eda Remove old unused display code 2018-07-29 19:53:41 -07:00
Aaron Culliney
409c4f39ad Update README.md 2018-07-29 19:00:30 -07:00
Aaron Culliney
b216d5f9f8 Include new test disk 2018-07-29 18:47:40 -07:00
Aaron Culliney
75edac3ace First cut at implementing conformant video scanner 2018-07-29 18:33:17 -07:00
Aaron Culliney
43ab5c8233 Implement a generic debugger hook to break stepping 2018-07-29 16:43:36 -07:00
Aaron Culliney
14bb75a941 Misc testing tweaks 2018-07-29 16:42:33 -07:00
Aaron Culliney
596f767b9a Updated generated file 2018-07-29 16:33:07 -07:00
Aaron Culliney
8f4e878919 Allow ignoring font mode in conversion 2018-07-29 16:31:10 -07:00
Aaron Culliney
a8e14381c1 Ensure disk_byte is properly reinitialized
- Improves CPU tracing against baseline
2018-07-29 16:28:56 -07:00
Aaron Culliney
7ac8f4303c Repurpose a softswitch printing function 2018-07-29 16:26:07 -07:00
Aaron Culliney
db8fb67944 Help Xcode/lldb cpu thread debugging on Intel by zeroing out the clobbered base pointer 2018-07-29 13:51:36 -07:00
Aaron Culliney
850b8f3b02 Include moar thingz, not necessarily for use by Apple2{Mac,iOS} ... 2018-05-06 10:15:03 -07:00
Aaron Culliney
e3c0c2550f Changes insisted upon by XCode 2018-05-06 10:14:56 -07:00
Aaron Culliney
aa41c89e68 Lite refactor video timing 2018-05-06 10:14:47 -07:00
Aaron Culliney
6ed0100291 More explicitly enable assert() in Droid release builds 2018-04-22 08:44:02 -07:00
Aaron Culliney
3318d159b5 mark expected assertion codepath 2018-04-22 08:43:57 -07:00
Aaron Culliney
234caa8c9c Consolidate hires page write handlers 2018-04-22 08:43:53 -07:00
Aaron Culliney
eb13718c5e Introduce CPU thread function annotation and enforcement 2018-04-22 08:43:16 -07:00
Aaron Culliney
51d2efba03 Streamline CPU tracing codepaths and remove some deadc0de 2018-03-31 12:48:14 -07:00
Aaron Culliney
1de71d1ff4 monocolor mode for LORES 2018-03-31 12:27:50 -07:00
Aaron Culliney
3c04e12db0 Add proper monocolor mode for HIRES80 2018-03-11 16:30:17 -07:00
Aaron Culliney
cedf7b9d0e Minor clean-up deadc0de in HGR40 generation 2018-03-11 16:28:07 -07:00
Aaron Culliney
154b9a7ef8 Fix Apple2Mac build 2018-01-22 07:33:33 -08:00
Aaron Culliney
dd42645c4c Silence some Xcode compiler warnings 2018-01-22 07:33:06 -08:00
Aaron Culliney
e898a85f50 Remove unneeded i86 assembly and fix iOS simulator build 2018-01-21 12:41:07 -08:00
Aaron Culliney
807b441ab1 Partial revert of "Mac app and tests build again"
This partially reverts commit 8f155b5190.
2018-01-20 17:42:04 -08:00
Aaron Culliney
4aa75a59c8 Change to automatic signing 2018-01-20 09:14:33 -08:00
Aaron Culliney
c1076aa9cf Upgrade to recommended Xcode settings and fix some build issues 2018-01-20 08:25:51 -08:00
Aaron Culliney
8f155b5190 Mac app and tests build again 2018-01-20 08:14:08 -08:00
Aaron Culliney
e4e0c941d3 Refactor CPU assembly for simplicity and efficiency
- Variables needed in assembly now accessible in a struct pointer that  avoids __PIC__ nastiness
    - Reduces code size and execution time for CPU thread
2018-01-15 16:19:21 -08:00
Aaron Culliney
6e7af373d7 Changes insisted upon by Android Studio 2018-01-15 10:17:46 -08:00
Aaron Culliney
167263ab3a Ensure starting with clean buffer ... 2018-01-15 10:17:02 -08:00
Aaron Culliney
b1161ba746 Bump Android version to 1.2.2 2017-12-03 13:44:04 -08:00
Aaron Culliney
6b901dff07 Avoid thread race with testprefs.c 2017-12-03 11:34:11 -08:00
Aaron Culliney
8b554083b4 Use "inverse" for keyboard selection color... 2017-11-26 16:20:05 -08:00
Aaron Culliney
cd6eb65fc5 Ensure color preferences set before any messaging on startup 2017-11-26 13:35:33 -08:00
Aaron Culliney
4bc61b6216 Allow access to system soft touch keyboard from top right menu 2017-11-26 13:35:04 -08:00
Aaron Culliney
20b085d9f7 Ensure that HUD color default matches true default 2017-11-26 11:35:10 -08:00
Aaron Culliney
a0c26386e8 malloc returns pointer ;) 2017-11-18 11:38:46 -08:00
Aaron Culliney
1ff7bfe4bf Use JDK 1.8 for the Java thingz 2017-11-18 11:28:55 -08:00
Aaron Culliney
7a99b72f20 Allow different colorschemes with HUD devices 2017-11-11 16:02:38 -08:00
Aaron Culliney
021604471b Avoid potential NPE 2017-11-11 12:06:26 -08:00
Aaron Culliney
dc5e7eee25 Allow showing system soft touch keyboard 2017-11-11 11:59:20 -08:00
Aaron Culliney
c3ea8c5aea Streamline configure checks and display disabled A/V systems 2017-09-28 16:28:10 -07:00
Aaron Culliney
53459c9e78 Clean up a number of Xcode build warnings 2017-09-28 16:27:12 -07:00
Aaron Culliney
570147712c Get Mac and iOS builds working again
- iOS build is still super Alpha ;)
2017-09-13 20:27:42 -07:00
Aaron Culliney
a9755215bf Native code builds again on Droid 2017-09-13 20:25:27 -07:00
Aaron Culliney
981cff845b Also convert '\n' to SCODE_RET 2017-09-09 18:08:49 -10:00
Aaron Culliney
b5b79faf1d First cut at CLI ncurses video renderer
- Currently supports 40/80col TEXT modes
    - TODO : graphics scaling
2017-09-09 18:06:43 -10:00
Aaron Culliney
dd02333eae Convert raw emulator key data to ASCII (or mousetext) 2017-09-09 16:59:55 -10:00
Aaron Culliney
a055ae8b8d Minimally begin to support UTF8 2017-09-09 16:57:06 -10:00
Aaron Culliney
25e4fd0eba Allow querying whether the classic interface is showing 2017-09-09 16:55:39 -10:00
Aaron Culliney
58d2392eac Name the running man glyph 2017-09-09 16:54:43 -10:00
Aaron Culliney
ae76537a19 Name colormap indices 2017-09-09 16:53:10 -10:00
Aaron Culliney
8e6701bcbb Allow CLI dynamic choice of A/V backends 2017-09-09 15:35:00 -10:00
Aaron Culliney
2517b45720 Silence a compile warning 2017-08-27 19:18:15 -10:00
Aaron Culliney
d35d87af9f Call open() with reasonable mode setting 2017-08-27 19:17:32 -10:00
Aaron Culliney
2d5c47d534 Autotools builds on Mac somewhat 2017-08-21 17:56:20 -10:00
Aaron Culliney
85dc4e5132 Move some sources into meta directory 2017-08-19 19:57:23 -10:00
Aaron Culliney
861cb3320c Display further refactored for text mode callbacks 2017-08-15 18:44:49 -10:00
Aaron Culliney
d226db8021 Better naming in font loading functions 2017-08-15 18:43:48 -10:00
Aaron Culliney
f8b4602fca Beginning to refactor display and backend video
- Futher disentangle display, interface, and video backends
    - Backend video owns the staging/intermediate framebuffer for now
    - Add the beginnings of display update callbacks
2017-08-06 12:12:12 -10:00
Aaron Culliney
0801c9f010 Be moar pessimistic about VAO availability
- TODO FIXME : refactor to dynamically check this
2017-07-31 17:49:53 -07:00
Aaron Culliney
72c5c550fe Always hide the system soft touch keyboard on Droid 'cause that keyboard is likely spying on you and we don't need it to party like it's 1987 :P 2017-07-31 17:49:29 -07:00
Aaron Culliney
11cf51753b Fix Desktop and Android builds after headless upheaval 2017-07-31 17:47:58 -07:00
Aaron Culliney
98aecedd65 Null renderer build can now execute tests 2017-07-30 12:42:31 -10:00
Aaron Culliney
bcbf5ac234 Refactor LOG() facilities
- Enable logging to file(s)
    - Enable log rotation
    - Allow silencing console logging (e.g., to stderr)
2017-07-30 12:24:48 -07:00
Aaron Culliney
1716dd35be Debugger and other meta code is now part of core emulator build 2017-07-30 10:11:47 -07:00
Aaron Culliney
153f1434db Rename GL_ERRLOG() to GL_MAYBELOG() 2017-07-15 15:08:42 -10:00
Aaron Culliney
51a5f5fcf7 Excise ERRLOG() in favor of LOG() 2017-07-15 14:39:15 -10:00
Aaron Culliney
3b1c72e872 Excise RELEASE_LOG() and RELEASE_BREAK() macros
- LOG() and assert() work just fine ;)
2017-07-15 14:19:31 -10:00
Aaron Culliney
3c1dcd4a69 Refactor to enable loading multiple AV backends
- Includes default 'null' backends with lowest priority
2017-07-15 13:25:00 -10:00
Aaron Culliney
97a98f0c86 Force X11 scaling to 2X and remove option for now 2017-07-15 13:16:50 -10:00
Aaron Culliney
bdbe544c3b Avoid SIGSEGV if glCheckFramebufferStatus not available 2017-07-09 15:41:43 -07:00
Aaron Culliney
13bf93e5ca Build release mode tests with NDEBUG=1 2017-07-09 11:09:11 -10:00
Aaron Culliney
2836d903d9 Bump Android version to 1.2.1 2017-07-09 07:24:24 -10:00
Aaron Culliney
a09d08c079 Changes insisted upon by Android Studio 2017-07-08 14:53:02 -10:00
Aaron Culliney
4885388a2d Bump Android version to 1.2.0 2017-07-08 14:51:11 -10:00
Aaron Culliney
aefe243620 Work around mysterious occasionally failing assert 2017-07-08 14:50:39 -10:00
Aaron Culliney
5102706441 Ensure that Apple2ix handles invalid gzipped files 2017-07-07 17:57:19 -10:00
Aaron Culliney
55cba116e4 Revert adding A2V3 format as it is unnecessary
- Re-gzipping ejected images is based solely on the file extension and not the actual file stream contents
    - Read/write disk images with extension ".gz" are re-gzipped in-place upon ejection
    - Read/write disk images without extension ".gz" are not changed upon ejection
    - Read-only disk images maintain current behavior (no modifications performed at all)
2017-07-06 19:36:37 -10:00
Aaron Culliney
f8b570869f Ensure we use run-as 2017-07-04 08:02:42 -10:00
Aaron Culliney
ccfaa0544a Explicitly test A2V3 data 2017-07-04 08:01:02 -10:00
Aaron Culliney
c00a52cbc6 unbreak testui 2017-07-04 08:00:52 -10:00
Aaron Culliney
b9c4ec4cc3 HACK : bump the timeout to get test passing on slow devices 2017-07-04 08:00:36 -10:00
Aaron Culliney
d872ad3cdd Add link to licenses page 2017-07-01 11:50:40 -10:00
Aaron Culliney
c30c50be06 Minor renaming of internal API function 2017-07-01 11:43:00 -07:00
Aaron Culliney
25a0f69a5f Clean up disk selection 2017-07-01 11:40:38 -07:00
Aaron Culliney
7411a987fa Disk chooser can now also choose .a2state files
- Internal save/restore API now uses file descriptors (supports restrictive app environments)
2017-07-01 11:03:15 -07:00
Aaron Culliney
d98c4afa84 Rename emulator.state to emulator.a2state and handle migration 2017-06-28 22:05:11 -07:00
Aaron Culliney
dacf0de80e More nonsensical changes that Android Studio insists upon making 2017-06-25 16:16:54 -07:00
Aaron Culliney
8e91d1f7de Clean up some Android cruft that we don't want to support (for now, possibly ever) because of platform fragmentation and rockstarz and ninjaz 2017-06-25 16:06:54 -07:00
Aaron Culliney
dd0de51d64 Disentangle new-school and old-school disk selection and misc cleanup 2017-06-13 09:51:52 -07:00
Aaron Culliney
2a263e2418 Avoid a crash in nativeStateExtractDiskPaths() 2017-06-07 02:21:48 -07:00
Aaron Culliney
c731c2a310 Do not show disk insertion dialog if nothing chosen 2017-06-05 16:41:17 -07:00
Aaron Culliney
e020817068 Bump Gradle version 2017-06-05 16:06:19 -07:00
Aaron Culliney
91fdf7b8e5 Add ability to choose disk images via the Android system chooser 2017-06-05 16:05:44 -07:00
Aaron Culliney
55ec0c7034 Unbreak Linux desktop build 2017-06-03 05:40:17 -07:00
Aaron Culliney
033dbf71ea Clean up disk/zlib internal APIs 2017-06-03 05:40:09 -07:00
Aaron Culliney
0468cea2d4 Clarify disk/zlib internal API comments after recent upheaval 2017-05-29 08:05:44 -10:00
Aaron Culliney
b300e60e2a Persist disk image 'was_gzipped' state
- 'was_gzipped' state is persisted in .apple2.json preferences
    - This removes all file-renaming codepaths at the cost of temporarily nonconformance to naming convesion (e.g., disk
      images inserted read/write are still called 'foo.dsk.gz' although they are not compressed)
    - Unclean shutdown of emulator leaves any disk images that were inserted read/write in their non-gzipped state
      (regardless of file name extension) on disk until emulator restarted and disk images explictly ejected or clean
      shudown.  App removal after unclean shutdown will potentially leave mis-named disk images lingering.
    - Emulator will handle edge cases of non-gzipped disk images with '.gz' extension and gzipped disk images without
      '.gz' extension
2017-05-29 08:05:38 -10:00
Aaron Culliney
399daf16fa More changes insisted upon by Android Studio 2017-05-28 10:09:14 -10:00
Aaron Culliney
8873fe09d1 U5 soft touch keyboard 2017-05-28 08:51:30 -10:00
Aaron Culliney
5dfa2e8797 Changes insisted upon by Android Studio 2017-05-28 08:49:38 -10:00
Aaron Culliney
4c893cc197 Beginnings of trace testing on Droid
- Currently broken because !CONFORMANT_TRACKS
2017-05-28 08:48:24 -10:00
Aaron Culliney
e1f0557b87 Allow loading test images from /sdcard/apple2ix on Android 2017-05-28 08:48:21 -10:00
Aaron Culliney
3de4a181eb Silence some build warnings on Android 2017-05-28 08:48:16 -10:00
Aaron Culliney
9bd59661ed Refactor disk image UI to use file descriptors and not paths
- Push path opening responsibility out of disk6 API in favor of using file descriptors
    - Improves handling of readonly gzipped disk images (now data is read without gunzipping or mmap()ing the file)
    - Currently represents an API-breaking change for macOS, iOS, GNU/Linux desktop ports (but should be easy to fix)
2017-05-28 08:48:11 -10:00
Aaron Culliney
2ca742650f Remove Intent handling of disk paths in preparation for refactoring this 2017-05-28 08:48:04 -10:00
Aaron Culliney
31aca92ffd video flags are unsigned long 2017-05-28 08:47:59 -10:00
Aaron Culliney
6bfbe3cc88 Bump Android version to 1.1.10 2016-11-07 19:37:24 -08:00
Aaron Culliney
14a40e055e Merge remote-tracking branch 'origin/droid-1.1.8.1' into aaron_experimental_rebase
Conflicts:
	Android/app/build.gradle
2016-11-07 19:36:59 -08:00
Aaron Culliney
bf0e61c9ea Android patch release 1.1.8.1 2016-11-05 11:43:42 -07:00
Aaron Culliney
96611beab9 Revert "Avoid doing Mockingboard work as much as possible"
This reverts commit 1bb3f75a06.

    - Caused excessive glitching in U4 music
2016-11-05 10:13:35 -07:00
Aaron Culliney
086c7e585a Update Android Studio 2016-10-30 12:18:23 -07:00
Aaron Culliney
a13caa8bd1 Bump Android version to 1.1.9 2016-10-30 11:43:23 -07:00
Aaron Culliney
6a630714ed Update README.md 2016-10-26 21:31:42 -07:00
Aaron Culliney
9cc3603d73 HACKishly fix macOS/iOS build 2016-10-26 21:23:34 -07:00
181 changed files with 25413 additions and 9652 deletions

1
Android/.idea/.name generated
View File

@@ -1 +0,0 @@
Android

29
Android/.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

View File

@@ -3,21 +3,15 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.14.1" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="myModules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>

22
Android/.idea/misc.xml generated
View File

@@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<list size="5">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
@@ -27,17 +25,7 @@
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

6
Android/.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="Android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id="Android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
@@ -13,7 +13,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="jdk" jdkName="JDK" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1 +1 @@
app/build/intermediates/manifests/full/debug/AndroidManifest.xml
app/build/intermediates/merged_manifests/debug/processDebugManifest/merged/AndroidManifest.xml

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
@@ -9,7 +9,6 @@
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
@@ -23,37 +22,45 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debug/processDebugResources/r" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debugAndroidTest/processDebugAndroidTestResources/r" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
@@ -61,7 +68,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
@@ -69,7 +75,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
@@ -77,48 +82,49 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotation_processor_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-compat/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-ui/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-utils/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-fragment/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-media-compat/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-libraries" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkDebugClasspath" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkReleaseClasspath" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" />
<orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="support-media-compat-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-compat-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-core-ui-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-core-utils-24.2.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-fragment-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-24.2.0" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-24.2.0" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-24.2.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-fragment-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:runtime-1.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core-1.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.1" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.1.0" level="project" />
</component>
</module>

View File

@@ -1,8 +1,7 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24"
compileSdkVersion 27
signingConfigs {
release {
storeFile file("release2.keystore")
@@ -28,10 +27,10 @@ android {
defaultConfig {
applicationId "org.deadc0de.apple2ix.basic"
minSdkVersion 10
targetSdkVersion 24
versionCode 18
versionName "1.1.8"
minSdkVersion 14
targetSdkVersion 27
versionCode 23
versionName "2.0.0"
ndk {
moduleName "apple2ix"
}
@@ -39,6 +38,6 @@ android {
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.0'
api fileTree(dir: 'libs', include: ['*.jar'])
api 'com.android.support:appcompat-v7:27.1.1'
}

View File

@@ -22,7 +22,8 @@
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"
android:screenOrientation="sensorLandscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:windowSoftInputMode="adjustResize" >
android:launchMode="singleTask"
android:windowSoftInputMode="stateHidden|adjustNothing" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -30,26 +31,23 @@
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.nib\\.gz" />
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.dsk\\.gz" />
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.do\\.gz" />
<data android:scheme="file" android:host="*" android:mimeType="application/x-gzip" android:pathPattern="/.*\\.po\\.gz" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" /> <!-- catch-all since I can't get the following to work because ... Android -->
<!--
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.nib" />
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.dsk" />
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.do" />
<data android:scheme="file" android:host="*" android:mimeType="application/octet-stream" android:pathPattern="/.*\\.po" />
-->
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="apple2ix" />
</intent-filter>
</activity>
<activity android:name="org.deadc0de.apple2ix.Apple2DiskChooserActivity" />
<provider
android:authorities="${applicationId}.provider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
</manifest>

View File

@@ -14,11 +14,12 @@ package org.deadc0de.apple2ix;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.StrictMode;
import android.util.Log;
import android.view.KeyEvent;
@@ -27,18 +28,22 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicBoolean;
import org.deadc0de.apple2ix.basic.BuildConfig;
import org.deadc0de.apple2ix.basic.R;
public class Apple2Activity extends Activity {
public class Apple2Activity extends Activity implements Apple2DiskChooserActivity.Callback {
private final static String TAG = "Apple2Activity";
private static volatile boolean DEBUG_STRICT = false;
private Apple2View mView = null;
@@ -53,6 +58,8 @@ public class Apple2Activity extends Activity {
private AtomicBoolean mPausing = new AtomicBoolean(false);
private AtomicBoolean mSwitchingToPortrait = new AtomicBoolean(false);
private static DiskArgs sDisksChosen = null;
// non-null if we failed to load/link the native code ... likely we are running on some bizarre 'droid variant
private static Throwable sNativeBarfedThrowable = null;
private static boolean sNativeBarfed = false;
@@ -68,15 +75,18 @@ public class Apple2Activity extends Activity {
public final static int REQUEST_PERMISSION_RWSTORE = 42;
private static native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
private static native void nativeOnKeyDown(int keyCode, int metaState);
private static native void nativeOnKeyUp(int keyCode, int metaState);
private static native void nativeSaveState(String path);
private static native void nativeSaveState(String saveStateJson);
private static native String nativeLoadState(String path);
private static native String nativeStateExtractDiskPaths(String extractStateJson);
private static native String nativeLoadState(String loadStateJson);
private static native boolean nativeEmulationResume();
@@ -91,7 +101,7 @@ public class Apple2Activity extends Activity {
}
@Override
public void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
if (Apple2Activity.DEBUG_STRICT && BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
@@ -136,12 +146,12 @@ public class Apple2Activity extends Activity {
boolean switchingToPortrait = Apple2VideoSettingsMenu.SETTINGS.applyLandscapeMode(this);
Apple2Preferences.sync(this, null);
Apple2DisksMenu.insertDisk((String) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A), /*driveA:*/true, (boolean) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO));
Apple2DisksMenu.insertDisk((String) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B), /*driveA:*/false, (boolean) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO));
Apple2DisksMenu.insertDisk(this, new DiskArgs((String) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A)), /*driveA:*/true, /*isReadOnly:*/(boolean) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO), /*onLaunch:*/true);
Apple2DisksMenu.insertDisk(this, new DiskArgs((String) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B)), /*driveA:*/false, /*isReadOnly:*/(boolean) Apple2Preferences.getJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO), /*onLaunch:*/true);
showSplashScreen(!firstTime);
// Is there a way to persist the user orientation setting such that we launch in the previously set orientation and avoid get multiple onCreate() onResume()?! ... Android lifecycle edge cases are so damn kludgishly annoying ...
// Is there a way to persist the user orientation setting such that we launch in the previously set orientation and avoid getting multiple onCreate() onResume()?! ... Android lifecycle edge cases are so damn kludgishly annoying ...
mSwitchingToPortrait.set(switchingToPortrait);
if (!switchingToPortrait) {
Apple2CrashHandler.getInstance().checkForCrashes(this);
@@ -150,16 +160,14 @@ public class Apple2Activity extends Activity {
boolean extperm = true;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// On Marshmallow+ specifically ask for permission to read/write storage
String readPermission = Manifest.permission.READ_EXTERNAL_STORAGE;
String writePermission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
int hasReadPermission = checkSelfPermission(readPermission);
int hasWritePermission = checkSelfPermission(writePermission);
int hasReadPermission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
int hasWritePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
ArrayList<String> permissions = new ArrayList<String>();
if (hasReadPermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(readPermission);
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(writePermission);
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissions.isEmpty()) {
extperm = false;
@@ -177,26 +185,35 @@ public class Apple2Activity extends Activity {
Apple2Utils.exposeAPKAssets(Apple2Activity.this);
if (externalStoragePermission) {
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
Log.d(TAG, "Finished first time copying #1...");
if (!(boolean)Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_RELEASE_NOTES, false)) {
Runnable myRunnable = new Runnable() {
@Override
public void run() {
showReleaseNotes();
}
};
new Handler(Apple2Activity.this.getMainLooper()).post(myRunnable);
}
}
mSplashScreen.setDismissable(true);
Log.d(TAG, "Finished first time copying...");
}
}).start();
}
mSettingsMenu = new Apple2SettingsMenu(this);
mDisksMenu = new Apple2DisksMenu(this);
}
Intent intent = getIntent();
String path = null;
if (intent != null) {
Uri data = intent.getData();
if (data != null) {
path = data.getPath();
}
}
if (path != null && Apple2DisksMenu.hasDiskExtension(path)) {
handleInsertDiskIntent(path);
@Override
public void onDisksChosen(DiskArgs args) {
final String name = args.name;
if (Apple2DisksMenu.hasDiskExtension(name) || Apple2DisksMenu.hasStateExtension(name)) {
sDisksChosen = args;
} else if (!name.equals("")) {
Toast.makeText(this, R.string.disk_insert_toast_cannot, Toast.LENGTH_SHORT).show();
}
}
@@ -212,27 +229,80 @@ public class Apple2Activity extends Activity {
}
}
if (grantedPermissions) {
// this will force copying APK files (now that we have permission
// perform migration(s) and assets exposure now
Apple2Utils.migrateToExternalStorage(Apple2Activity.this);
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
Log.d(TAG, "Finished first time copying #2...");
} // else ... we keep nagging on app startup ...
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
if (!(boolean)Apple2Preferences.getJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_RELEASE_NOTES, false)) {
showReleaseNotes();
}
}
@Override
protected void onResume() {
super.onResume();
if (sNativeBarfed) {
Apple2CrashHandler.getInstance().abandonAllHope(this, sNativeBarfedThrowable);
return;
}
Log.d(TAG, "onResume()");
showSplashScreen(/*dismissable:*/true);
if (!mSwitchingToPortrait.get()) {
Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
}
do {
if (sNativeBarfed) {
Apple2CrashHandler.getInstance().abandonAllHope(this, sNativeBarfedThrowable);
break;
}
Log.d(TAG, "onResume()");
showSplashScreen(/*dismissable:*/true);
if (!mSwitchingToPortrait.get()) {
Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
}
if (mDisksMenu == null) {
break;
}
if (sDisksChosen == null) {
break;
}
DiskArgs args = sDisksChosen;
sDisksChosen = null;
if (args.pfd == null) {
break;
}
String name = args.name;
if (Apple2DisksMenu.hasStateExtension(name)) {
boolean restored = Apple2MainMenu.restoreEmulatorState(this, args);
dismissAllMenus();
if (!restored) {
Toast.makeText(this, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
}
break;
}
final String[] prefices = {"content://com.android.externalstorage.documents/document", "content://com.android.externalstorage.documents", "content://com.android.externalstorage.documents", "content://"};
for (String prefix : prefices) {
if (name.startsWith(prefix)) {
name = name.substring(prefix.length());
break;
}
}
// strip out URL-encoded '/' directory separators
String nameLower = name.toLowerCase();
int idx = nameLower.lastIndexOf("%2f", /*fromIndex:*/name.length() - 3);
if (idx >= 0) {
name = name.substring(idx + 3);
}
mDisksMenu.showDiskInsertionAlertDialog(name, args);
} while (false);
}
@Override
@@ -315,6 +385,59 @@ public class Apple2Activity extends Activity {
}
}
public void showReleaseNotes() {
Apple2Preferences.setJSONPref(Apple2Preferences.PREF_DOMAIN_INTERFACE, Apple2Preferences.PREF_RELEASE_NOTES, true);
Apple2Preferences.save(this);
String releaseNotes = "";
final int maxAttempts = 5;
int attempts = 0;
do {
InputStream is = null;
try {
AssetManager assetManager = getAssets();
is = assetManager.open("release_notes.txt");
final int bufferSize = 4096;
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
Reader in = new InputStreamReader(is, "UTF-8");
while (true) {
int siz = in.read(buffer, 0, buffer.length);
if (siz < 0) {
break;
}
out.append(buffer, 0, siz);
}
releaseNotes = out.toString();
break;
} catch (InterruptedIOException e) {
/* EINTR, EAGAIN */
} catch (IOException e) {
Log.e(TAG, "OOPS could not load release_notes.txt!", e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// NOOP
}
}
}
++attempts;
} while (attempts < maxAttempts);
AlertDialog.Builder builder = new AlertDialog.Builder(Apple2Activity.this).setIcon(R.drawable.ic_launcher).setCancelable(false).setTitle(R.string.release_notes).setMessage(releaseNotes).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
registerAndShowDialog(dialog);
}
public Apple2MainMenu getMainMenu() {
return mMainMenu;
}
@@ -327,60 +450,6 @@ public class Apple2Activity extends Activity {
return mSettingsMenu;
}
private void handleInsertDiskIntent(final String path) {
runOnUiThread(new Runnable() {
@Override
public void run() {
synchronized (Apple2Activity.this) {
if (mMainMenu == null) {
return;
}
String diskPath = path;
File diskFile = new File(diskPath);
if (!diskFile.canRead()) {
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_could_not_read), Toast.LENGTH_SHORT).show();
return;
}
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO, true);
final int len = diskPath.length();
final String suffix = diskPath.substring(len - 3, len);
if (suffix.equalsIgnoreCase(".gz")) { // HACK FIXME TODO : small amount of code duplication of Apple2DisksMenu
diskPath = diskPath.substring(0, len - 3);
}
Apple2DisksMenu.insertDisk(diskPath, /*driveA:*/true, /*readOnly:*/true);
while (mDisksMenu.popPathStack() != null) {
/* ... */
}
File storageDir = Apple2Utils.getExternalStorageDirectory(Apple2Activity.this);
if (storageDir != null) {
String storagePath = storageDir.getAbsolutePath();
if (diskPath.contains(storagePath)) {
diskPath = diskPath.replace(storagePath + File.separator, "");
mDisksMenu.pushPathStack(storagePath);
}
}
StringTokenizer tokenizer = new StringTokenizer(diskPath, File.separator);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (token.equals("")) {
continue;
}
if (Apple2DisksMenu.hasDiskExtension(token)) {
continue;
}
mDisksMenu.pushPathStack(token);
}
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_toast), Toast.LENGTH_SHORT).show();
}
}
});
}
public Apple2SplashScreen getSplashScreen() {
return mSplashScreen;
}
@@ -389,6 +458,7 @@ public class Apple2Activity extends Activity {
if (mSplashScreen != null) {
return;
}
mSplashScreen = new Apple2SplashScreen(this, dismissable);
mSplashScreen.show();
}
@@ -508,10 +578,7 @@ public class Apple2Activity extends Activity {
public void maybeResumeEmulation() {
if (mMenuStack.size() == 0 && !mPausing.get()) {
Apple2Preferences.sync(this, null);
boolean previouslyPaused = nativeEmulationResume();
if (BuildConfig.DEBUG && !previouslyPaused) {
throw new RuntimeException("expecting native CPU thread to have been paused");
}
nativeEmulationResume();
}
}
@@ -526,12 +593,16 @@ public class Apple2Activity extends Activity {
nativeReboot(resetState);
}
public void saveState(String stateFile) {
nativeSaveState(stateFile);
public void saveState(String saveStateJson) {
nativeSaveState(saveStateJson);
}
public String loadState(String stateFile) {
return Apple2Activity.nativeLoadState(stateFile);
public String stateExtractDiskPaths(String extractStateJson) {
return nativeStateExtractDiskPaths(extractStateJson);
}
public String loadState(String loadStateJson) {
return nativeLoadState(loadStateJson);
}
public void quitEmulator() {

View File

@@ -0,0 +1,191 @@
/*
* Apple // emulator for *nix
*
* This software package is subject to the GNU General Public License
* version 3 or later (your choice) as published by the Free Software
* Foundation.
*
* Copyright 2017 Aaron Culliney
*
*/
package org.deadc0de.apple2ix;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.concurrent.atomic.AtomicBoolean;
public class Apple2DiskChooserActivity extends Activity {
public static final AtomicBoolean sDiskChooserIsChoosing = new AtomicBoolean(false);
public static Callback sDisksCallback;
public interface Callback {
void onDisksChosen(DiskArgs args);
}
@Nullable
public static ParcelFileDescriptor openFileDescriptorFromUri(Context ctx, Uri uri) {
ParcelFileDescriptor pfd = null;
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
throw new RuntimeException("SDK Version not allowed access");
}
if (!DocumentsContract.isDocumentUri(ctx, uri)) {
throw new RuntimeException("Not a Document URI for " + uri);
}
ContentResolver resolver = ctx.getContentResolver();
resolver.takePersistableUriPermission(uri, (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
pfd = resolver.openFileDescriptor(uri, "rw");
} catch (Throwable t) {
Log.e(TAG, "OOPS, could not get appropriate access to URI ( " + uri + " ) : " + t);
}
return pfd;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("ran", true);
}
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
Bundle b;
{
Intent intent = getIntent();
Bundle extras = null;
if (intent != null) {
extras = intent.getExtras();
}
if (savedState != null) {
b = savedState;
} else if (extras != null) {
b = extras;
} else {
b = new Bundle();
}
}
boolean ran = b.getBoolean("ran");
if (ran) {
Log.e(TAG, "OOPS, already ran...");
finish();
return;
}
////Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
Intent pickIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
try {
pickIntent.setType("*/*");
pickIntent.addCategory(Intent.CATEGORY_OPENABLE);
/* FIXME TODO : currently we don't have decent UI/UX for multi-select ...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
pickIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}*/
if (!ran) {
startActivityForResult(pickIntent, EDIT_REQUEST_CODE);
}
} catch (Throwable t) {
Log.e(TAG, "OOPS : " + t);
setResult(RESULT_CANCELED);
finish();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_CANCELED) {
/* FIXME TODO : currently we don't have decent UI/UX for multi-select ...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ClipData clipData = null;
if (data != null) {
clipData = data.getClipData();
}
if (clipData != null && clipData.getItemCount() > 1) {
uris = new Uri[2];
uris[0] = clipData.getItemAt(0).getUri();
uris[1] = clipData.getItemAt(1).getUri();
}
}*/
if (chosenUri == null) {
if (data != null) {
chosenUri = data.getData();
}
}
if (chosenUri != null) {
chosenPfd = openFileDescriptorFromUri(this, chosenUri);
}
}
setResult(RESULT_OK);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public void finish() {
sDiskChooserIsChoosing.set(false);
String name = chosenUri == null ? "" : chosenUri.toString();
if (sDisksCallback != null) {
sDisksCallback.onDisksChosen(new DiskArgs(name, chosenUri, chosenPfd));
}
super.finish();
}
private Uri chosenUri;
private ParcelFileDescriptor chosenPfd;
private static final String TAG = "A2DiskChooserActivity";
private static final int EDIT_REQUEST_CODE = 44;
}
class DiskArgs {
public String name;
public String path;
public Uri uri;
public ParcelFileDescriptor pfd;
public DiskArgs(String name, Uri uri, ParcelFileDescriptor pfd) {
this.name = name;
this.uri = uri;
this.pfd = pfd;
}
public DiskArgs(String path) {
this.path = path;
}
}

View File

@@ -14,7 +14,10 @@ package org.deadc0de.apple2ix;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -22,26 +25,33 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import org.deadc0de.apple2ix.basic.R;
import org.json.JSONObject;
public class Apple2DisksMenu implements Apple2MenuView {
private final static String TAG = "Apple2DisksMenu";
public final static String EXTERNAL_CHOOSER_SENTINEL = "apple2ix://";
private Apple2Activity mActivity = null;
private View mDisksView = null;
@@ -49,9 +59,9 @@ public class Apple2DisksMenu implements Apple2MenuView {
private static boolean sInitializedPath = false;
private static native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
private static native String nativeChooseDisk(String jsonData);
private static native void nativeEjectDisk(boolean driveA);
private static native void nativeEjectDisk(boolean isDriveA);
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
CURRENT_DISK_SEARCH_PATH {
@@ -79,12 +89,12 @@ public class Apple2DisksMenu implements Apple2MenuView {
CURRENT_DISK_RO_BUTTON {
@Override
public String getPrefKey() {
return "driveACurrent";
return "driveRO";
}
@Override
public Object getPrefDefault() {
return true;
return false;
}
},
CURRENT_DISK_PATH_A {
@@ -106,7 +116,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
@Override
public Object getPrefDefault() {
return true;
return false;
}
},
CURRENT_DISK_PATH_B {
@@ -128,7 +138,19 @@ public class Apple2DisksMenu implements Apple2MenuView {
@Override
public Object getPrefDefault() {
return true;
return false;
}
},
USE_NEWSCHOOL_DISK_SELECTION {
@Override
public String getPrefKey() {
return "useNewSchoolDiskSelection";
}
@Override
public Object getPrefDefault() {
// 2017/06/30 NOTE : keep this default false to accommodate initial installs that only have access to shipped public domain images
return false;
}
};
@@ -172,6 +194,44 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
});
for (int i = 0; i < 2; i++) {
final Button ejectButton = (Button) mDisksView.findViewById(i == 0 ? R.id.ejectButton1 : R.id.ejectButton2);
final int idx = i;
ejectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ejectDisk(/*isDriveA:*/idx == 0);
dynamicSetup();
}
});
}
final CheckBox newschoolSelection = (CheckBox) mDisksView.findViewById(R.id.newschoolDiskSelectionButton);
newschoolSelection.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Apple2Preferences.setJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION, newschoolSelection.isChecked());
dynamicSetup();
}
});
final View newschoolChooser = mDisksView.findViewById(R.id.disk_selection_newschool_chooser);
newschoolChooser.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final boolean alreadyChoosing = Apple2DiskChooserActivity.sDiskChooserIsChoosing.getAndSet(true);
if (alreadyChoosing) {
return;
}
Intent chooserIntent = new Intent(mActivity, Apple2DiskChooserActivity.class);
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION/* | Intent.FLAG_ACTIVITY_CLEAR_TOP */);
Apple2DiskChooserActivity.sDisksCallback = mActivity;
mActivity.startActivity(chooserIntent);
}
});
Apple2Utils.getExternalStorageDirectory(activity);
}
@@ -199,7 +259,11 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
public void dismiss() {
String path = popPathStack();
String path = null;
if (!(boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION)) {
path = popPathStack();
}
if (path == null) {
mActivity.popApple2View(this);
} else {
@@ -254,14 +318,40 @@ public class Apple2DisksMenu implements Apple2MenuView {
return path;
}
public static void insertDisk(String fullPath, boolean isDriveA, boolean isReadOnly) {
File file = new File(fullPath);
final String imageName = fullPath;
if (!file.exists()) {
fullPath = fullPath + ".gz";
file = new File(fullPath);
}
if (file.exists()) {
public static void insertDisk(Apple2Activity activity, DiskArgs diskArgs, boolean isDriveA, boolean isReadOnly, boolean onLaunch) {
try {
JSONObject map = new JSONObject();
ejectDisk(isDriveA);
String imageName = diskArgs.path;
if (imageName == null) {
imageName = EXTERNAL_CHOOSER_SENTINEL + diskArgs.uri.toString();
}
if (imageName.startsWith(EXTERNAL_CHOOSER_SENTINEL)) {
if (!Apple2Utils.isExternalStorageAccessible(activity)) {
// disallow access if we cannot access external storage
throw new Exception("External storage not accessible");
}
if (diskArgs.pfd == null) {
if (diskArgs.uri == null) {
String uriString = imageName.substring(EXTERNAL_CHOOSER_SENTINEL.length());
diskArgs.uri = Uri.parse(uriString);
}
diskArgs.pfd = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, diskArgs.uri);
}
int fd = diskArgs.pfd.getFd(); // NPE thrown if diskArgs.pfd is null
map.put("fd", fd);
} else {
File file = new File(imageName);
if (!file.exists()) {
throw new RuntimeException("cannot insert : " + imageName);
}
}
if (isDriveA) {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A_RO, isReadOnly);
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, imageName);
@@ -269,12 +359,98 @@ public class Apple2DisksMenu implements Apple2MenuView {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B_RO, isReadOnly);
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, imageName);
}
nativeChooseDisk(fullPath, isDriveA, isReadOnly);
} else {
Log.d(TAG, "Cannot insert: " + fullPath);
map.put("disk", imageName);
map.put("drive", isDriveA ? "0" : "1");
map.put("readOnly", isReadOnly ? "true" : "false");
String jsonString = nativeChooseDisk(map.toString());
if (diskArgs.pfd != null) {
try {
diskArgs.pfd.close();
} catch (IOException ioe) {
Log.e(TAG, "Error attempting to close PFD : " + ioe);
}
}
diskArgs.pfd = null;
map = new JSONObject(jsonString);
boolean inserted = map.getBoolean("inserted");
if (!inserted) {
ejectDisk(isDriveA);
}
} catch (Throwable t) {
Log.d(TAG, "OOPS: " + t);
}
}
public static void ejectDisk(boolean isDriveA) {
if (isDriveA) {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, "");
} else {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, "");
}
nativeEjectDisk(isDriveA);
}
public void showDiskInsertionAlertDialog(String title, final DiskArgs diskArgs) {
title = mActivity.getResources().getString(R.string.header_disks) + " " + title;
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setCancelable(true).setMessage(title);
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View diskConfirmationView = inflater.inflate(R.layout.a2disk_confirmation, null, false);
builder.setView(diskConfirmationView);
final RadioButton driveA = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskA);
boolean driveAChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DRIVE_A);
driveA.setChecked(driveAChecked);
driveA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DRIVE_A, isChecked);
}
});
final RadioButton driveB = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskB);
driveB.setChecked(!driveAChecked);
final RadioButton readOnly = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readOnly);
boolean roChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON);
readOnly.setChecked(roChecked);
readOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON, isChecked);
}
});
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
readWrite.setChecked(!roChecked);
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
boolean isDriveA = driveA.isChecked();
boolean diskReadOnly = readOnly.isChecked();
insertDisk(mActivity, diskArgs, isDriveA, diskReadOnly, /*onLaunch:*/false);
dialog.dismiss();
mActivity.dismissAllMenus();
}
});
AlertDialog dialog = builder.create();
mActivity.registerAndShowDialog(dialog);
}
public static boolean hasDiskExtension(String name) {
@@ -317,6 +493,20 @@ public class Apple2DisksMenu implements Apple2MenuView {
return (suffix.equalsIgnoreCase(".dsk.gz") || suffix.equalsIgnoreCase(".nib.gz"));
}
public static boolean hasStateExtension(String name) {
// check file extensions ... sigh ... no String.endsWithIgnoreCase() ?
final int extLen = Apple2MainMenu.SAVE_FILE_EXTENSION.length();
final int len = name.length();
if (len <= extLen) {
return false;
}
final String suffix = name.substring(len - extLen, len);
return suffix.equalsIgnoreCase(Apple2MainMenu.SAVE_FILE_EXTENSION);
}
// ------------------------------------------------------------------------
// internals ...
@@ -335,11 +525,87 @@ public class Apple2DisksMenu implements Apple2MenuView {
private void dynamicSetup() {
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
disksList.setEnabled(true);
final boolean useNewschoolSelection = (boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION);
final CheckBox newschoolSelection = (CheckBox) mDisksView.findViewById(R.id.newschoolDiskSelectionButton);
newschoolSelection.setChecked(useNewschoolSelection);
final boolean isKitKatOrBetter = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT);
final boolean includeExternalFileChooser = Apple2Utils.isExternalStorageAccessible(mActivity) && isKitKatOrBetter;
final View newschoolChooser = mDisksView.findViewById(R.id.disk_selection_newschool_chooser);
if (!includeExternalFileChooser || !useNewschoolSelection) {
disksList.setEnabled(true);
disksList.setVisibility(View.VISIBLE);
newschoolChooser.setVisibility(View.INVISIBLE);
for (int i = 0; i < 2; i++) {
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
layout.setVisibility(View.INVISIBLE);
}
if (!includeExternalFileChooser) {
newschoolSelection.setVisibility(View.INVISIBLE);
}
Apple2Preferences.setJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION, false);
oldschoolDynamicSetup();
return;
}
disksList.setEnabled(false);
disksList.setVisibility(View.INVISIBLE);
newschoolChooser.setVisibility(View.VISIBLE);
// new external file chooser activity can allow navigation to restricted external SD Card(s) ...
newschoolSelection.setVisibility(View.VISIBLE);
for (int i = 0; i < 2; i++) {
String imageName = null;
do {
String diskPath = (String) Apple2Preferences.getJSONPref((i == 0) ? SETTINGS.CURRENT_DISK_PATH_A : SETTINGS.CURRENT_DISK_PATH_B);
if (diskPath == null || diskPath.equals("")) {
break;
}
Uri uri = Uri.parse(diskPath);
if (uri == null) {
break;
}
diskPath = uri.getPath();
int idx = diskPath.lastIndexOf("/");
if (idx < 0) {
break;
}
imageName = diskPath.substring(idx + 1);
} while (false);
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
if (imageName == null || imageName.equals("")) {
layout.setVisibility(View.INVISIBLE);
} else {
layout.setVisibility(View.VISIBLE);
boolean readOnly = (boolean) Apple2Preferences.getJSONPref((i == 0) ? SETTINGS.CURRENT_DISK_PATH_A_RO : SETTINGS.CURRENT_DISK_PATH_B_RO);
imageName = "(" + mActivity.getResources().getString((readOnly ? R.string.disk_read_only : R.string.disk_read_write)) + "): " + imageName;
TextView textView = (TextView) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_diskA : R.id.a2_newschool_diskB);
textView.setText(imageName);
}
}
}
private void oldschoolDynamicSetup() {
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
String disksDir = pathStackAsDirectory();
final boolean isRootPath = (disksDir == null);
final File extStorageDir = Apple2Utils.getExternalStorageDirectory(mActivity);
if (isRootPath) {
disksDir = Apple2Utils.getDataDir(mActivity) + File.separator + "disks"; // default path
}
@@ -359,7 +625,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
return false;
}
File file = new File(dir, name);
return file.isDirectory() || hasDiskExtension(name);
return file.isDirectory() || hasDiskExtension(name) || hasStateExtension(name);
}
});
@@ -388,14 +654,15 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
}
final boolean includeExternalStoragePath = (extStorageDir != null && isRootPath);
final boolean includeExternalStoragePath = (Apple2Utils.isExternalStorageAccessible(mActivity) && isRootPath);
final int offset = includeExternalStoragePath ? 1 : 0;
final String[] fileNames = new String[files.length + offset];
final String[] filePaths = new String[files.length + offset];
final boolean[] isDirectory = new boolean[files.length + offset];
int idx = 0;
// first external storage link should be /sdcard/apple2ix to encourage this form of organization
if (includeExternalStoragePath) {
filePaths[idx] = Apple2Utils.getRealExternalStorageDirectory(mActivity).getAbsolutePath();
fileNames[idx] = mActivity.getResources().getString(R.string.storage);
@@ -437,12 +704,6 @@ public class Apple2DisksMenu implements Apple2MenuView {
} else {
String imageName = files[position - offset].getAbsolutePath();
final int len = imageName.length();
final String suffix = imageName.substring(len - 3, len);
if (suffix.equalsIgnoreCase(".gz")) {
imageName = files[position - offset].getAbsolutePath().substring(0, len - 3);
}
String eject = mActivity.getResources().getString(R.string.disk_eject);
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_A))) {
Button ejectButton = new Button(mActivity);
@@ -450,8 +711,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
ejectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
nativeEjectDisk(/*driveA:*/true);
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, "");
ejectDisk(/*driveA:*/true);
dynamicSetup();
}
});
@@ -462,8 +722,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
ejectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
nativeEjectDisk(/*driveA:*/false);
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, "");
ejectDisk(/*driveA:*/false);
dynamicSetup();
}
});
@@ -495,84 +754,29 @@ public class Apple2DisksMenu implements Apple2MenuView {
return;
}
String str = files[position - offset].getAbsolutePath();
final int len = str.length();
final String suffix = str.substring(len - 3, len);
if (suffix.equalsIgnoreCase(".gz")) {
str = files[position - offset].getAbsolutePath().substring(0, len - 3);
}
final String imageName = str;
final String imageName = files[position - offset].getAbsolutePath();
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_A))) {
nativeEjectDisk(/*driveA:*/true);
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, "");
ejectDisk(/*isDriveA:*/true);
dynamicSetup();
return;
}
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_B))) {
nativeEjectDisk(/*driveA:*/false);
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, "");
ejectDisk(/*isDriveA:*/false);
dynamicSetup();
return;
}
String title = mActivity.getResources().getString(R.string.header_disks);
title = title + " " + fileNames[position];
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setCancelable(true).setMessage(title);
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View diskConfirmationView = inflater.inflate(R.layout.a2disk_confirmation, null, false);
builder.setView(diskConfirmationView);
final RadioButton driveA = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskA);
boolean driveAChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DRIVE_A);
driveA.setChecked(driveAChecked);
driveA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DRIVE_A, isChecked);
if (hasStateExtension(imageName)) {
final String jsonString = "{ \"stateFile\" : \"" + imageName + "\" }";
final boolean restored = Apple2MainMenu.restoreEmulatorState(mActivity, jsonString);
mActivity.dismissAllMenus();
if (!restored) {
Toast.makeText(mActivity, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
}
});
final RadioButton driveB = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskB);
driveB.setChecked(!driveAChecked);
return;
}
final RadioButton readOnly = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readOnly);
boolean roChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON);
readOnly.setChecked(roChecked);
readOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON, isChecked);
}
});
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
readWrite.setChecked(!roChecked);
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
boolean isDriveA = driveA.isChecked();
boolean diskReadOnly = readOnly.isChecked();
if (isDriveA) {
insertDisk(imageName, /*driveA:*/true, diskReadOnly);
} else {
insertDisk(imageName, /*driveA:*/false, diskReadOnly);
}
dialog.dismiss();
mActivity.dismissAllMenus();
}
});
AlertDialog dialog = builder.create();
mActivity.registerAndShowDialog(dialog);
showDiskInsertionAlertDialog(/*title:*/fileNames[position], /*diskPath:*/new DiskArgs(imageName));
}
});
}

View File

@@ -15,7 +15,9 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -23,23 +25,26 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import org.deadc0de.apple2ix.basic.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
public class Apple2MainMenu {
public final static String SAVE_FILE = "emulator.state";
public final static String OLD_SAVE_FILE = "emulator.state";
public final static String SAVE_FILE_EXTENSION = ".a2state";
public final static String SAVE_FILE = "emulator" + SAVE_FILE_EXTENSION;
private final static String TAG = "Apple2MainMenu";
private Apple2Activity mActivity = null;
@@ -262,7 +267,7 @@ public class Apple2MainMenu {
final RadioButton noAppleSelected = (RadioButton) resetConfirmationView.findViewById(R.id.radioButton_noApple);
noAppleSelected.setChecked(false);
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setPositiveButton(R.string.reset, new DialogInterface.OnClickListener() {
AlertDialog rebootQuitDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setView(resetConfirmationView).setPositiveButton(R.string.reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
@@ -287,16 +292,136 @@ public class Apple2MainMenu {
}
mActivity.quitEmulator();
}
}).setNegativeButton(R.string.cancel, null);
builder.setView(resetConfirmationView);
AlertDialog rebootQuitDialog = builder.create();
}).setNegativeButton(R.string.cancel, null).create();
mActivity.registerAndShowDialog(rebootQuitDialog);
}
public static boolean restoreEmulatorState(Apple2Activity activity, DiskArgs diskArgs) {
boolean restored = false;
public void maybeSaveRestore() {
try {
String stateFile = diskArgs.path;
if (stateFile == null) {
stateFile = Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL + diskArgs.uri.toString();
}
JSONObject map = new JSONObject();
map.put("stateFile", stateFile);
if (stateFile.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
if (!Apple2Utils.isExternalStorageAccessible(activity)) {
// disallow access if we cannot access external storage
throw new Exception("External storage not accessible for state load");
}
if (diskArgs.pfd == null) {
if (diskArgs.uri == null) {
String uriString = stateFile.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
diskArgs.uri = Uri.parse(uriString);
}
diskArgs.pfd = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, diskArgs.uri);
}
int fd = diskArgs.pfd.getFd(); // NPE thrown if diskArgs.pfd is null
map.put("fdState", fd);
} else {
File file = new File(stateFile);
if (!file.exists()) {
throw new RuntimeException("cannot insert state file : " + stateFile);
}
}
restored = restoreEmulatorState(activity, map.toString());
try {
diskArgs.pfd.close(); // at this point diskArgs.pfd !null
} catch (IOException ioe) {
Log.e(TAG, "Error attempting to close PFD : " + ioe);
}
diskArgs.pfd = null;
} catch (Exception e) {
Log.e(TAG, "OOPS: " + e);
}
return restored;
}
public static boolean restoreEmulatorState(Apple2Activity activity, String jsonString) {
boolean restored = false;
Apple2DisksMenu.ejectDisk(/*isDriveA:*/true);
Apple2DisksMenu.ejectDisk(/*isDriveA:*/false);
// First we extract and open the emulator.a2state disk paths (which could be in a restricted location)
jsonString = activity.stateExtractDiskPaths(jsonString);
try {
JSONObject map = new JSONObject(jsonString);
final String[] diskPathKeys = new String[]{"diskA", "diskB"};
final String[] readOnlyKeys = new String[]{"readOnlyA", "readOnlyB"};
final String[] fdKeys = new String[]{"fdA", "fdB"};
ParcelFileDescriptor[] pfds = {null, null};
for (int i = 0; i < 2; i++) {
String diskPath = map.getString(diskPathKeys[i]);
boolean readOnly = map.getBoolean(readOnlyKeys[i]);
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B, diskPath);
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO, readOnly);
if (diskPath.equals("")) {
continue;
}
if (diskPath.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
String uriString = diskPath.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
Uri uri = Uri.parse(uriString);
pfds[i] = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, uri);
if (pfds[i] == null) {
Log.e(TAG, "Did not find URI for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
} else {
int fd = pfds[i].getFd();
map.put(fdKeys[i], fd);
}
} else {
boolean exists = new File(diskPath).exists();
if (!exists) {
Log.e(TAG, "Did not find path for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
}
}
}
jsonString = activity.loadState(map.toString());
for (int i = 0; i < 2; i++) {
try {
if (pfds[i] != null) {
pfds[i].close();
}
} catch (IOException ioe) {
Log.e(TAG, "Error attempting to close PFD #" + i + " : " + ioe);
}
}
map = new JSONObject(jsonString);
restored = map.getBoolean("loadStateSuccess");
} catch (Throwable t) {
Log.v(TAG, "OOPS : " + t);
}
return restored;
}
private void maybeSaveRestore() {
mActivity.pauseEmulation();
final String quickSavePath;
@@ -317,31 +442,24 @@ public class Apple2MainMenu {
Log.v(TAG, "OMG, avoiding nasty UI race in sync/restore onClick()");
return;
}
mActivity.saveState(quickSavePath);
String jsonString = "{ \"stateFile\" : \"" + quickSavePath + "\" }";
mActivity.saveState(jsonString);
Apple2MainMenu.this.dismiss();
}
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
Log.v(TAG, "OMG, avoiding nasty UI race in sync/restore onClick()");
return;
}
String jsonData = mActivity.loadState(quickSavePath);
try {
JSONObject map = new JSONObject(jsonData);
String diskPath1 = map.getString("disk1");
boolean readOnly1 = map.getBoolean("readOnly1");
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A, diskPath1);
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO, readOnly1);
String diskPath2 = map.getString("disk2");
boolean readOnly2 = map.getBoolean("readOnly2");
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B, diskPath2);
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO, readOnly2);
} catch (JSONException je) {
Log.v(TAG, "OOPS : " + je);
final String jsonString = "{ \"stateFile\" : \"" + quickSavePath + "\" }";
boolean restored = restoreEmulatorState(mActivity, jsonString);
if (!restored) {
Toast.makeText(mActivity, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
}
Apple2MainMenu.this.dismiss();
}

View File

@@ -48,6 +48,7 @@ public class Apple2Preferences {
public final static String PREF_DEVICE_HEIGHT = "deviceHeight";
public final static String PREF_DEVICE_WIDTH = "deviceWidth";
public final static String PREF_EMULATOR_VERSION = "emulatorVersion";
public final static String PREF_RELEASE_NOTES = "shownReleaseNotes";
// JSON preferences
private static JSONObject sSettings = null;
@@ -174,8 +175,15 @@ public class Apple2Preferences {
Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME);
setJSONPref(PREF_DOMAIN_INTERFACE, PREF_EMULATOR_VERSION, BuildConfig.VERSION_CODE);
setJSONPref(PREF_DOMAIN_INTERFACE, PREF_RELEASE_NOTES, false);
Apple2Utils.migrate(activity);
if (versionCode < 22) {
// force upgrade to defaults here ...
setJSONPref(Apple2VideoSettingsMenu.SETTINGS.SHOW_HALF_SCANLINES, Apple2VideoSettingsMenu.SETTINGS.SHOW_HALF_SCANLINES.getPrefDefault());
setJSONPref(Apple2VideoSettingsMenu.SETTINGS.COLOR_MODE_CONFIGURE, Apple2VideoSettingsMenu.SETTINGS.COLOR_MODE_CONFIGURE.getPrefDefault());
}
Apple2Utils.migrateToExternalStorage(activity);
if (BuildConfig.VERSION_CODE >= 17) {
// FIXME TODO : remove this after most/all app users are on 18+
@@ -208,7 +216,7 @@ public class Apple2Preferences {
switch (key) {
case "HIRES_COLOR": // long
menuEnum = Apple2VideoSettingsMenu.SETTINGS.COLOR_CONFIGURE;
menuEnum = Apple2VideoSettingsMenu.SETTINGS.COLOR_MODE_CONFIGURE;
break;
case "LANDSCAPE_MODE": // bool
menuEnum = Apple2VideoSettingsMenu.SETTINGS.LANDSCAPE_MODE;

View File

@@ -248,6 +248,57 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
return convertView;
}
},
FAST_DISK_OPERATIONS {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.disk_fast_operation);
}
@Override
public final String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.disk_fast_operation_summary);
}
@Override
public String getPrefKey() {
return "diskFastLoading";
}
@Override
public Object getPrefDefault() {
return false;
}
@Override
public View getView(final Apple2Activity activity, View convertView) {
final IMenuEnum self = this;
convertView = _basicView(activity, this, convertView);
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref(self, isChecked);
}
});
return convertView;
}
},
RELEASE_NOTES {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.release_notes);
}
@Override
public final String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.release_notes_summary);
}
@Override
public void handleSelection(Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
activity.showReleaseNotes();
}
},
ABOUT {
@Override
public final String getTitle(Apple2Activity activity) {
@@ -267,6 +318,25 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
activity.startActivity(i);
}
},
LICENSES {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.about_apple2ix_licenses);
}
@Override
public final String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.about_apple2ix_licenses_summary);
}
@Override
public void handleSelection(Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
String url = "https://deadc0de.org/apple2ix/licenses/";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
activity.startActivity(i);
}
},
RESET_PREFERENCES {
@Override
public final String getTitle(Apple2Activity activity) {

View File

@@ -29,6 +29,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
@@ -102,49 +103,59 @@ public class Apple2Utils {
return attempts < maxAttempts;
}
public static void migrate(Apple2Activity activity) {
public static void migrateToExternalStorage(Apple2Activity activity) {
do {
if (BuildConfig.VERSION_CODE >= 18) {
// Migrate emulator.state file from internal path to external storage to allow user manipulation
// Rename old emulator state file
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
final File extStorage = Apple2Utils.getExternalStorageDirectory(activity);
if (extStorage == null) {
break;
}
final String srcPath = getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE;
final File srcFile = new File(srcPath);
final File srcFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.OLD_SAVE_FILE);
if (!srcFile.exists()) {
break;
}
final String dstPath = extStorage + File.separator + Apple2MainMenu.SAVE_FILE;
final File dstFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE);
final boolean success = copyFile(srcFile, dstFile);
if (success) {
srcFile.delete();
}
}
} while (false);
final int maxAttempts = 5;
int attempts = 0;
do {
try {
FileInputStream is = new FileInputStream(srcFile);
FileOutputStream os = new FileOutputStream(dstPath);
copyFile(is, os);
break;
} catch (InterruptedIOException e) {
// EINTR, EAGAIN ...
} catch (IOException e) {
Log.d(TAG, "OOPS exception attempting to copy emulator.state file : " + e);
}
try {
Thread.sleep(100, 0);
} catch (InterruptedException ie) {
// ...
}
++attempts;
} while (attempts < maxAttempts);
final File extStorage = Apple2Utils.getExternalStorageDirectory(activity);
if (extStorage == null) {
return;
}
srcFile.delete();
do {
if (BuildConfig.VERSION_CODE >= 18) {
// Migrate old emulator state file from internal path to external storage to allow user manipulation
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
final File srcFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE);
if (!srcFile.exists()) {
break;
}
final File dstFile = new File(extStorage + File.separator + Apple2MainMenu.SAVE_FILE);
final boolean success = copyFile(srcFile, dstFile);
if (success) {
srcFile.delete();
}
}
} while (false);
do {
if (BuildConfig.VERSION_CODE >= 20) {
// Recursively rename all *.state files found in /sdcard/apple2ix
// TODO FIXME : Remove this migration code when all/most users are on version >= 20
recursivelyRenameEmulatorStateFiles(extStorage);
}
} while (false);
}
@@ -188,6 +199,11 @@ public class Apple2Utils {
return sRealExternalFilesDir;
}
public static boolean isExternalStorageAccessible(Apple2Activity activity) {
getExternalStorageDirectory(activity);
return (sRealExternalFilesDir != null) && (new File(sRealExternalFilesDir.getAbsolutePath()).listFiles() != null);
}
// HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources
// out of the APK and into the /data/data/... for ease of access. Because this is FOSS software we don't care about
// security or DRM for these assets =)
@@ -397,6 +413,85 @@ public class Apple2Utils {
} while (attempts < maxAttempts);
}
private static void recursivelyRenameEmulatorStateFiles(File directory) {
try {
if (!directory.isDirectory()) {
return;
}
final int oldSuffixLen = 6;
File[] files = directory.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.equals(".") || name.equals("..")) {
return false;
}
final File file = new File(dir, name);
if (file.isDirectory()) {
return true;
}
final int len = name.length();
if (len < oldSuffixLen) {
return false;
}
final String suffix = name.substring(len - oldSuffixLen, len);
return suffix.equalsIgnoreCase(".state");
}
});
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
recursivelyRenameEmulatorStateFiles(file);
} else {
final File srcFile = file;
final String oldName = file.getName();
final String newName = oldName.substring(0, oldName.length() - oldSuffixLen) + Apple2MainMenu.SAVE_FILE_EXTENSION;
boolean success = file.renameTo(new File(file.getParentFile(), newName));
if (success) {
srcFile.delete();
}
}
}
} catch (Exception e) {
Log.e(TAG, "OOPS : {e}");
}
}
private static boolean copyFile(final File srcFile, final File dstFile) {
final int maxAttempts = 5;
int attempts = 0;
do {
try {
FileInputStream is = new FileInputStream(srcFile);
FileOutputStream os = new FileOutputStream(dstFile);
copyFile(is, os);
break;
} catch (InterruptedIOException e) {
// EINTR, EAGAIN ...
} catch (IOException e) {
Log.d(TAG, "OOPS exception attempting to copy emulator state file : " + e);
}
try {
Thread.sleep(100, 0);
} catch (InterruptedException ie) {
// ...
}
++attempts;
} while (attempts < maxAttempts);
return attempts < maxAttempts;
}
private static void copyFile(InputStream is, OutputStream os) throws IOException {
final int BUF_SZ = 4096;
byte[] buf = new byte[BUF_SZ];
@@ -410,4 +505,3 @@ public class Apple2Utils {
os.flush();
}
}

View File

@@ -56,10 +56,33 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
return true;
}
public enum HiresColor {
BW,
COLOR,
INTERPOLATED
public enum ColorMode {
COLOR_MODE_MONO,
COLOR_MODE_COLOR,
COLOR_MODE_INTERP,
COLOR_MODE_COLOR_MONITOR,
COLOR_MODE_MONO_TV,
COLOR_MODE_COLOR_TV,
}
public enum MonoMode {
MONO_MODE_BW,
MONO_MODE_GREEN,
}
// must match interface_colorscheme_t
public enum DeviceColor {
GREEN_ON_BLACK(0),
GREEN_ON_BLUE(1), // ...
RED_ON_BLACK(2),
BLUE_ON_BLACK(3),
WHITE_ON_BLACK(4);
private int val;
DeviceColor(int val) {
this.val = val;
}
}
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
@@ -97,7 +120,7 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref((IMenuEnum)self, isChecked);
Apple2Preferences.setJSONPref((IMenuEnum) self, isChecked);
applyLandscapeMode(activity);
}
});
@@ -144,7 +167,7 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
}
}
},
COLOR_CONFIGURE {
COLOR_MODE_CONFIGURE {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.color_configure);
@@ -167,7 +190,103 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
@Override
public Object getPrefDefault() {
return HiresColor.INTERPOLATED.ordinal();
return ColorMode.COLOR_MODE_COLOR_TV.ordinal();
}
@Override
public View getView(Apple2Activity activity, View convertView) {
convertView = _basicView(activity, this, convertView);
_addPopupIcon(activity, this, convertView);
return convertView;
}
@Override
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
final Apple2AbstractMenu.IMenuEnum self = this;
_alertDialogHandleSelection(activity, R.string.video_configure, new String[]{
settingsMenu.mActivity.getResources().getString(R.string.color_mono),
settingsMenu.mActivity.getResources().getString(R.string.color_color),
settingsMenu.mActivity.getResources().getString(R.string.color_interpolated),
settingsMenu.mActivity.getResources().getString(R.string.color_monitor),
settingsMenu.mActivity.getResources().getString(R.string.color_tv_mono),
settingsMenu.mActivity.getResources().getString(R.string.color_tv),
}, new IPreferenceLoadSave() {
@Override
public int intValue() {
return (int) Apple2Preferences.getJSONPref(self);
}
@Override
public void saveInt(int value) {
Apple2Preferences.setJSONPref(self, ColorMode.values()[value].ordinal());
}
});
}
},
SHOW_HALF_SCANLINES {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.show_half_scanlines);
}
@Override
public final String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.show_half_scanlines_summary);
}
@Override
public String getPrefDomain() {
return Apple2Preferences.PREF_DOMAIN_VIDEO;
}
@Override
public String getPrefKey() {
return "showHalfScanlines";
}
@Override
public Object getPrefDefault() {
return true;
}
@Override
public View getView(final Apple2Activity activity, View convertView) {
final IMenuEnum self = this;
convertView = _basicView(activity, this, convertView);
CheckBox cb = _addCheckbox(activity, this, convertView, (boolean) Apple2Preferences.getJSONPref(this));
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.setJSONPref(self, isChecked);
}
});
return convertView;
}
},
MONO_MODE_CONFIGURE {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.mono_configure);
}
@Override
public final String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.mono_configure_summary);
}
@Override
public String getPrefDomain() {
return Apple2Preferences.PREF_DOMAIN_VIDEO;
}
@Override
public String getPrefKey() {
return "monoMode";
}
@Override
public Object getPrefDefault() {
return MonoMode.MONO_MODE_BW.ordinal();
}
@Override
@@ -182,8 +301,7 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
final Apple2AbstractMenu.IMenuEnum self = this;
_alertDialogHandleSelection(activity, R.string.video_configure, new String[]{
settingsMenu.mActivity.getResources().getString(R.string.color_bw),
settingsMenu.mActivity.getResources().getString(R.string.color_color),
settingsMenu.mActivity.getResources().getString(R.string.color_interpolated),
settingsMenu.mActivity.getResources().getString(R.string.color_green),
}, new IPreferenceLoadSave() {
@Override
public int intValue() {
@@ -192,7 +310,83 @@ public class Apple2VideoSettingsMenu extends Apple2AbstractMenu {
@Override
public void saveInt(int value) {
Apple2Preferences.setJSONPref(self, HiresColor.values()[value].ordinal());
Apple2Preferences.setJSONPref(self, MonoMode.values()[value].ordinal());
}
});
}
},
COLOR_DEVICE_CONFIGURE {
@Override
public final String getTitle(Apple2Activity activity) {
return activity.getResources().getString(R.string.touch_device_color);
}
@Override
public final String getSummary(Apple2Activity activity) {
return activity.getResources().getString(R.string.touch_device_color_summary);
}
@Override
public String getPrefDomain() {
return Apple2Preferences.PREF_DOMAIN_INTERFACE;
}
@Override
public String getPrefKey() {
return "hudColorMode";
}
@Override
public Object getPrefDefault() {
return DeviceColor.RED_ON_BLACK.ordinal();
}
@Override
public View getView(Apple2Activity activity, View convertView) {
convertView = _basicView(activity, this, convertView);
_addPopupIcon(activity, this, convertView);
return convertView;
}
@Override
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
final Apple2AbstractMenu.IMenuEnum self = this;
_alertDialogHandleSelection(activity, R.string.touch_device_color_configure, new String[]{
settingsMenu.mActivity.getResources().getString(R.string.color_red_on_black),
settingsMenu.mActivity.getResources().getString(R.string.color_green_on_black),
settingsMenu.mActivity.getResources().getString(R.string.color_blue_on_black),
settingsMenu.mActivity.getResources().getString(R.string.color_white_on_black),
}, new IPreferenceLoadSave() {
@Override
public int intValue() {
int colorscheme = (int) Apple2Preferences.getJSONPref(self);
if (colorscheme == DeviceColor.GREEN_ON_BLACK.ordinal()) {
return 1;
} else if (colorscheme == DeviceColor.BLUE_ON_BLACK.ordinal()) {
return 2;
} else if (colorscheme == DeviceColor.WHITE_ON_BLACK.ordinal()) {
return 3;
} else {
return 0;
}
}
@Override
public void saveInt(int value) {
switch (value) {
case 1:
Apple2Preferences.setJSONPref(self, (int) DeviceColor.GREEN_ON_BLACK.ordinal());
break;
case 2:
Apple2Preferences.setJSONPref(self, (int) DeviceColor.BLUE_ON_BLACK.ordinal());
break;
case 3:
Apple2Preferences.setJSONPref(self, (int) DeviceColor.WHITE_ON_BLACK.ordinal());
break;
default:
Apple2Preferences.setJSONPref(self, (int) DeviceColor.RED_ON_BLACK.ordinal());
break;
}
}
});
}

View File

@@ -26,6 +26,7 @@ import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import com.example.inputmanagercompat.InputManagerCompat;
@@ -42,6 +43,7 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
public final static long NATIVE_TOUCH_HANDLED = (1 << 0);
public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1);
public final static long NATIVE_TOUCH_REQUEST_SHOW_SYSTEM_KBD = (1 << 2);
public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4);
public final static long NATIVE_TOUCH_KBD = (1 << 5);
@@ -519,6 +521,16 @@ class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDevice
apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode);
}
}
if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_SYSTEM_KBD) != 0) {
clearFocus();
requestFocus();
InputMethodManager inputMethodManager = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager != null) {
inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_FORCED);
}
}
} while (false);
return true;

View File

@@ -43,6 +43,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/a2preference_title"
android:layout_alignLeft="@id/a2preference_title"
android:layout_alignStart="@id/a2preference_title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="4" />

View File

@@ -1,39 +1,212 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/black"
android:orientation="vertical"
android:baselineAligned="false"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
android:layout_height="fill_parent"
android:layout_marginBottom="5dip"
android:layout_marginLeft="5dip"
android:layout_marginStart="5dip"
android:layout_marginRight="5dip"
android:layout_marginEnd="5dip"
android:layout_marginTop="5dip"
android:background="@color/black"
android:layout_weight="1">
<!-- disk selection header -->
<LinearLayout
android:background="@color/black"
android:orientation="horizontal"
android:baselineAligned="false"
android:id="@+id/disks_selection_header"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- newschool checkbox -->
<CheckBox
android:id="@+id/newschoolDiskSelectionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/disk_selection_newschoool" />
<!-- spacer that works with API 10 ... -->
<TextView
android:id="@+id/header_disks"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="@string/header_disks" />
android:layout_weight="1" />
<Button
android:id="@+id/ejectButton1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@android:drawable/ic_menu_close_clear_cancel"
android:drawableStart="@android:drawable/ic_menu_close_clear_cancel"
android:id="@+id/cancelButton" />
android:text="@string/header_eject_1" />
<Button
android:id="@+id/ejectButton2"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/header_eject_2" />
<!-- spacer that works with API 10 ... -->
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1" />
<Button
android:id="@+id/cancelButton"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableEnd="@android:drawable/ic_menu_close_clear_cancel"
android:drawableRight="@android:drawable/ic_menu_close_clear_cancel" />
</LinearLayout>
<!-- oldschool list view -->
<ListView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="@+id/listView_settings"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignLeft="@id/disks_selection_header"
android:layout_alignStart="@id/disks_selection_header"
android:layout_below="@id/disks_selection_header"
android:visibility="invisible"
android:layout_weight="1" />
</LinearLayout>
<!-- newschool file chooser -->
<LinearLayout
android:id="@+id/disk_selection_newschool_chooser"
android:layout_alignLeft="@id/disks_selection_header"
android:layout_alignStart="@id/disks_selection_header"
android:layout_below="@id/disks_selection_header"
android:layout_marginLeft="5dip"
android:layout_marginStart="5dip"
android:layout_marginRight="5dip"
android:layout_marginEnd="5dip"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_marginTop="20dip"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:text="@string/file_chooser"
android:textAppearance="?android:attr/textAppearanceLarge" />
<!-- spacer that works with API 10 ... -->
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1" />
<ImageView
android:src="@android:drawable/ic_menu_save"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- newschool drive A selection -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/a2_newschool_driveA_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/disk_selection_newschool_chooser"
android:layout_alignStart="@id/disk_selection_newschool_chooser"
android:layout_below="@id/disk_selection_newschool_chooser"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingLeft="0dp"
android:paddingStart="0dp"
android:paddingRight="?android:attr/scrollbarSize"
android:paddingEnd="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:layout_marginRight="5dip"
android:layout_marginEnd="5dip"
android:layout_marginTop="5dip"
android:layout_weight="1">
<TextView
android:id="@+id/a2_newschool_driveA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:text="@string/diskA"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/a2_newschool_diskA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/a2_newschool_driveA"
android:layout_alignStart="@id/a2_newschool_driveA"
android:layout_below="@id/a2_newschool_driveA"
android:maxLines="4"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
</LinearLayout>
<!-- newschool drive B selection -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/a2_newschool_driveB_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/a2_newschool_driveA_layout"
android:layout_alignStart="@id/a2_newschool_driveA_layout"
android:layout_below="@id/a2_newschool_driveA_layout"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingLeft="0dp"
android:paddingStart="0dp"
android:paddingRight="?android:attr/scrollbarSize"
android:paddingEnd="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="5dip"
android:layout_weight="1">
<TextView
android:id="@+id/a2_newschool_driveB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:text="@string/diskB"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/a2_newschool_diskB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/a2_newschool_driveB"
android:layout_alignStart="@id/a2_newschool_driveB"
android:layout_below="@id/a2_newschool_driveB"
android:maxLines="4"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View File

@@ -15,6 +15,8 @@
<!-- main options -->
<string name="about_apple2ix">Über Apple2ix…</string>
<string name="about_apple2ix_summary">Über diese Software</string>
<string name="about_apple2ix_licenses">Licenses…</string>
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
<string name="app_name">Apple2ix</string>
<string name="audio_configure">Audio-Konfiguration…</string>
<string name="audio_configure_summary">Lautstärke, Mockingboard, etc</string>
@@ -32,15 +34,18 @@
<string name="diskA">Laufwerk 1</string>
<string name="diskB">Laufwerk 2</string>
<string name="disk_eject">Auswerfen</string>
<string name="disk_insert_toast">Die eingelegte Diskette ist schreibgeschützt</string>
<string name="disk_insert_could_not_read">Entschuldigung, das Diskettenabbild konnte nicht gelesen werden!</string>
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
<string name="disk_read_only">Schreibgeschützt</string>
<string name="disk_read_write">Lesen/Schreiben</string>
<string name="disk_selection_newschoool">System chooser</string>
<string name="disk_show_operation">Zeige Disk ][ Aktivität</string>
<string name="disk_show_operation_summary">Zeigt wenn die Laufwerke lesen oder schreiben</string>
<string name="emulation_continue">Fortsetzen…</string>
<string name="emulation_disks">Lade Disk-Image…</string>
<string name="file_chooser">Choose disk image or state file…</string>
<string name="header_disks">Diskette einlegen:</string>
<string name="header_eject_1">Auswerfen 1</string>
<string name="header_eject_2">Auswerfen 2</string>
<string name="input_current">Aktuelles Touch Device</string>
<string name="input_current_summary">Wähle ein aktuelles Touch Device</string>
<string name="joystick">Joystick</string>
@@ -127,7 +132,7 @@
<string name="mockingboard_disabled_title">Mockingboard deaktiviert</string>
<string name="mockingboard_disabled_mesg">Mockingboard konnte nicht aktiviert werden</string>
<string name="mockingboard_enable">Aktiviere Mockingboard</string>
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (evtl. wird ein Restart benötigt)</string>
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (evtl. wird ein Restart benötigt) (may consume extra battery)</string>
<string name="mockingboard_volume">Mockingboard Lautstärke</string>
<string name="mockingboard_volume_summary">Einstellen der Mockingboard Lautstärke</string>
<string name="no">Nein</string>
@@ -138,7 +143,7 @@
<string name="preferences_reset_warning">Sie werden alle Ihre Einstellungen verlieren</string>
<string name="quit">Beenden</string>
<string name="quit_reboot">Neustart oder beenden des Emulators…</string>
<string name="quit_reboot_choice">Neustart oder beenden?</string>
<string name="quit_reboot_choice">Neustart oder beenden?&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#13;&#10;</string>
<string name="reboot">Neustart</string>
<string name="restore">Schnelle Wiederherstellung</string>
<string name="save">Schnelle Speicherung</string>
@@ -157,8 +162,8 @@
<string name="touch_menu_enable_summary">Aktiviere Softmenü Knöpfe in den oberen Ecken des Bildschirms</string>
<string name="video_configure">Video-Konfiguration…</string>
<string name="video_configure_summary">Farbeinstellungen</string>
<string name="color_configure">Configure color</string>
<string name="color_configure_summary">Color mode</string>
<string name="color_configure">Video display mode</string>
<string name="color_configure_summary">Video display emulation mode</string>
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
<string name="mode_landscape">Landscape</string>
@@ -174,5 +179,27 @@
<string name="reset_preferences">Reset settings</string>
<string name="reset_self_test">Self Test</string>
<string name="reset_soft">Soft</string>
<string name="touch_device_color">Configure touch device color</string>
<string name="touch_device_color_summary">Configure color of HUD elements</string>
<string name="state_not_restored">Error restoring state…</string>
<string name="storage">/storage/</string>
<string name="touch_device_color_configure">Configure HUD color…</string>
<string name="color_red_on_black">Red on black</string>
<string name="color_green_on_black">Green on black</string>
<string name="color_blue_on_black">Blue on black</string>
<string name="color_white_on_black">White on black</string>
<string name="color_monitor">Color Monitor</string>
<string name="color_tv_mono">Monochrome TV</string>
<string name="color_tv">Color TV</string>
<string name="show_half_scanlines">Show half scanlines</string>
<string name="mono_configure">Monocolor mode</string>
<string name="mono_configure_summary">Configure monochrome color</string>
<string name="color_green">Green screen</string>
<string name="color_mono">Monochrome</string>
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
<string name="release_notes">Release notes</string>
<string name="release_notes_summary">View notes for this release</string>
</resources>

View File

@@ -15,6 +15,8 @@
<!-- main options -->
<string name="about_apple2ix">Acerca de Apple2ix…</string>
<string name="about_apple2ix_summary">Acerca de este software</string>
<string name="about_apple2ix_licenses">Licenses…</string>
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
<string name="app_name">Apple2ix</string>
<string name="audio_configure">Configurar audio…</string>
<string name="audio_configure_summary">Ajustar el volumen del altavoz, "Mockingboard", etc</string>
@@ -32,15 +34,18 @@
<string name="diskA">Disquetera 1</string>
<string name="diskB">Disquetera 2</string>
<string name="disk_eject">Eyectar</string>
<string name="disk_insert_toast">Disco insertado en la disquetera de sólo lectura</string>
<string name="disk_insert_could_not_read">Lo sentimos, no se puede leer la imagen de disquete!</string>
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
<string name="disk_read_only">Sólo leer</string>
<string name="disk_read_write">Leer y escribir</string>
<string name="disk_selection_newschoool">System chooser</string>
<string name="disk_show_operation">Mostrar las operaciones de "Disk ]["</string>
<string name="disk_show_operation_summary">Shows when disk drives are reading or writing</string>
<string name="emulation_continue">Continuar…</string>
<string name="emulation_disks">Insertar imagen de disquete…</string>
<string name="file_chooser">Choose disk image or state file…</string>
<string name="header_disks">Insertar imagen de disquete:</string>
<string name="header_eject_1">Eyectar 1</string>
<string name="header_eject_2">Eyectar 2</string>
<string name="input_current">Unidad de entrada actual</string>
<string name="input_current_summary">Elija unidad de entrada</string>
<string name="joystick">"Joystick"</string>
@@ -125,7 +130,7 @@
<string name="mockingboard_disabled_title">Mockingboard desactivado</string>
<string name="mockingboard_disabled_mesg">Mockingboard no pudo ser habilitado</string>
<string name="mockingboard_enable">Activar Mockingboard</string>
<string name="mockingboard_enable_summary">Revisión C en la ranura 4/5 puede requerir reinicio</string>
<string name="mockingboard_enable_summary">Revisión C en Slot 4/5 (puede requerir reinicio) (may consume extra battery)</string>
<string name="mockingboard_volume">Volumen de Mockingboard</string>
<string name="mockingboard_volume_summary">Adjustar el volumen del Mockingboard</string>
<string name="no">No</string>
@@ -136,7 +141,7 @@
<string name="preferences_reset_warning">Usted perderá su configuración</string>
<string name="quit">Salir</string>
<string name="quit_reboot">Reiniciar o salir el emulador…</string>
<string name="quit_reboot_choice">¿Reiniciar o salir?</string>
<string name="quit_reboot_choice">¿Reiniciar o salir?&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#13;&#10;</string>
<string name="reboot">Reiniciar</string>
<string name="restore">Restauración rápida</string>
<string name="save">Guardar rápido</string>
@@ -155,8 +160,8 @@
<string name="touch_menu_enable_summary">Los botones del menú en la parte superior de la pantalla</string>
<string name="video_configure">Configurar el video…</string>
<string name="video_configure_summary">Ajustes de color</string>
<string name="color_configure">Configure color</string>
<string name="color_configure_summary">Color mode</string>
<string name="color_configure">Video display mode</string>
<string name="color_configure_summary">Video display emulation mode</string>
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
<string name="mode_landscape">Landscape</string>
@@ -174,5 +179,27 @@
<string name="reset_preferences">Reset settings</string>
<string name="reset_self_test">Self Test</string>
<string name="reset_soft">Soft</string>
<string name="touch_device_color">Configure touch device color</string>
<string name="touch_device_color_summary">Configure color of HUD elements</string>
<string name="state_not_restored">Error restoring state…</string>
<string name="storage">/storage/</string>
<string name="touch_device_color_configure">Configure HUD color…</string>
<string name="color_red_on_black">Red on black</string>
<string name="color_green_on_black">Green on black</string>
<string name="color_blue_on_black">Blue on black</string>
<string name="color_white_on_black">White on black</string>
<string name="color_monitor">Color Monitor</string>
<string name="color_tv_mono">Monochrome TV</string>
<string name="color_tv">Color TV</string>
<string name="show_half_scanlines">Show half scanlines</string>
<string name="mono_configure">Monocolor mode</string>
<string name="mono_configure_summary">Configure monochrome color</string>
<string name="color_green">Green screen</string>
<string name="color_mono">Monochrome</string>
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
<string name="release_notes">Release notes</string>
<string name="release_notes_summary">View notes for this release</string>
</resources>

View File

@@ -15,6 +15,8 @@
<!-- main options -->
<string name="about_apple2ix">A propos d\'Apple2ix…</string>
<string name="about_apple2ix_summary">A propos de ce logiciel</string>
<string name="about_apple2ix_licenses">Licenses…</string>
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
<string name="app_name">Apple2ix</string>
<string name="audio_configure">Configuration audio…</string>
<string name="audio_configure_summary">Volume du haut-parleur, Mockingboard, etc</string>
@@ -32,15 +34,18 @@
<string name="diskA">Lecteur 1</string>
<string name="diskB">Lecteur 2</string>
<string name="disk_eject">Ejecter</string>
<string name="disk_insert_toast">Insérer la disquette dans le drive en lecture seulement</string>
<string name="disk_insert_could_not_read">Désolé, impossible de lire l\'image disque!</string>
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
<string name="disk_selection_newschoool">System chooser</string>
<string name="disk_read_only">Lecture seulement</string>
<string name="disk_read_write">Lecture/Ecriture</string>
<string name="disk_show_operation">Afficher les opérations (disque) ][</string>
<string name="disk_show_operation_summary">Indique si les disques sont en lecture ou en écriture</string>
<string name="emulation_continue">Continuer…</string>
<string name="emulation_disks">Chargement de l\'image disque…</string>
<string name="file_chooser">Choose disk image or state file…</string>
<string name="header_disks">Insérer la disquettte :</string>
<string name="header_eject_1">Ejecter 1</string>
<string name="header_eject_2">Ejecter 2</string>
<string name="input_current">Tactile</string>
<string name="input_current_summary">Choisir l\'appareil courant</string>
<string name="joystick">Joystick</string>
@@ -125,7 +130,7 @@
<string name="mockingboard_disabled_title">Mockingboard désactivé</string>
<string name="mockingboard_disabled_mesg">Le Mockingboard ne peut être activé</string>
<string name="mockingboard_enable">Activer le Mockingboard</string>
<string name="mockingboard_enable_summary">Révision C dans Slot 4/5 (redémarrage possible)</string>
<string name="mockingboard_enable_summary">Révision C dans Slot 4/5 (redémarrage possible) (may consume extra battery)</string>
<string name="mockingboard_volume">Volume du Mockingboard</string>
<string name="mockingboard_volume_summary">Placer le volume du Mockingboard</string>
<string name="no">Non</string>
@@ -136,7 +141,7 @@
<string name="preferences_reset_warning">Vous perdrez toutes vos options de configuration</string>
<string name="quit">Quitter</string>
<string name="quit_reboot">Rebooter ou quitter l\'émulateur…</string>
<string name="quit_reboot_choice">Rebooter ou quitter?</string>
<string name="quit_reboot_choice">Rebooter ou quitter?&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#13;&#10;</string>
<string name="reboot">Rebooter</string>
<string name="restore">Restauration rapide</string>
<string name="save">Sauvegarde rapide</string>
@@ -155,8 +160,8 @@
<string name="touch_menu_enable_summary">Activation soft des bouton du menu dans les coins en haut de l\'écran</string>
<string name="video_configure">Configuration de la vidéo…</string>
<string name="video_configure_summary">Configuration des couleurs</string>
<string name="color_configure">Configure color</string>
<string name="color_configure_summary">Color mode</string>
<string name="color_configure">Video display mode</string>
<string name="color_configure_summary">Video display emulation mode</string>
<string name="joystick_azimuth_visible">Show joystick/keypad heading</string>
<string name="joystick_azimuth_visible_summary">Shows current axis direction and magnitude</string>
<string name="mode_landscape">Landscape</string>
@@ -174,5 +179,27 @@
<string name="reset_self_test">Self Test</string>
<string name="reset_preferences">Reset settings</string>
<string name="reset_soft">Soft</string>
<string name="touch_device_color">Configure touch device color</string>
<string name="touch_device_color_summary">Configure color of HUD elements</string>
<string name="state_not_restored">Error restoring state…</string>
<string name="storage">/storage/</string>
<string name="touch_device_color_configure">Configure HUD color…</string>
<string name="color_red_on_black">Red on black</string>
<string name="color_green_on_black">Green on black</string>
<string name="color_blue_on_black">Blue on black</string>
<string name="color_white_on_black">White on black</string>
<string name="color_monitor">Color Monitor</string>
<string name="color_tv_mono">Monochrome TV</string>
<string name="color_tv">Color TV</string>
<string name="show_half_scanlines">Show half scanlines</string>
<string name="mono_configure">Monocolor mode</string>
<string name="mono_configure_summary">Configure monochrome color</string>
<string name="color_green">Green screen</string>
<string name="color_mono">Monochrome</string>
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
<string name="release_notes">Release notes</string>
<string name="release_notes_summary">View notes for this release</string>
</resources>

View File

@@ -17,14 +17,16 @@
<!-- main options -->
<string name="about_apple2ix">About Apple2ix…</string>
<string name="about_apple2ix_summary">About this software</string>
<string name="about_apple2ix_licenses">Licenses…</string>
<string name="about_apple2ix_licenses_summary">Apple2ix software licenses</string>
<string name="app_name">Apple2ix</string>
<string name="audio_configure">Configure audio…</string>
<string name="audio_configure_summary">Speaker volume, Mockingboard, etc</string>
<string name="audio_latency">Audio latency</string>
<string name="audio_latency_summary">Audio latency in secs</string>
<string name="cancel">Cancel</string>
<string name="color_configure">Configure color</string>
<string name="color_configure_summary">Color mode</string>
<string name="color_configure">Video display mode</string>
<string name="color_configure_summary">Video display emulation mode</string>
<string name="color_bw">Black/white</string>
<string name="color_color">Color</string>
<string name="color_interpolated">Interpolated color</string>
@@ -36,15 +38,18 @@
<string name="diskA">Drive 1</string>
<string name="diskB">Drive 2</string>
<string name="disk_eject">Eject</string>
<string name="disk_insert_toast">Inserted disk in drive read-only</string>
<string name="disk_insert_could_not_read">Sorry, could not read the disk image!</string>
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
<string name="disk_read_only">Read only</string>
<string name="disk_read_write">Read/write</string>
<string name="disk_selection_newschoool">System chooser</string>
<string name="disk_show_operation">Show Disk ][ operations</string>
<string name="disk_show_operation_summary">Shows when disk drives are reading or writing</string>
<string name="emulation_continue">Continue…</string>
<string name="emulation_disks">Load disk image</string>
<string name="file_chooser">Choose disk image or state file…</string>
<string name="header_disks">Insert disk:</string>
<string name="header_eject_1">Eject 1</string>
<string name="header_eject_2">Eject 2</string>
<string name="input_current">Current touch device</string>
<string name="input_current_summary">Choose current touch device</string>
<string name="joystick">Joystick</string>
@@ -126,14 +131,14 @@
<string name="keypad_preset_left_right_space">&#8592;,&#8594;, tap spacebar</string>
<string name="keypad_preset_wadx_space">W,A,D,X, tap spacebar</string>
<string name="keypad_repeat_summary">Key repeat threshold in secs</string>
<string name="menu_disks">Load disk image…</string>
<string name="menu_disks_summary">Insert a Disk ][ image file</string>
<string name="menu_disks">Load image or state file…</string>
<string name="menu_disks_summary">Insert Disk ][ image or state file</string>
<string name="menu_settings">Emulator settings…</string>
<string name="menu_settings_summary">General settings, joystick, keyboard</string>
<string name="mockingboard_disabled_title">Mockingboard disabled</string>
<string name="mockingboard_disabled_mesg">Mockingboard could not be enabled</string>
<string name="mockingboard_enable">Enable Mockingboard</string>
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (may require restart)</string>
<string name="mockingboard_enable_summary">Revision C in Slot 4/5 (may require restart) (may consume extra battery)</string>
<string name="mockingboard_volume">Mockingboard volume</string>
<string name="mockingboard_volume_summary">Set the Mockingboard volume</string>
<string name="mode_landscape">Landscape</string>
@@ -151,7 +156,7 @@
<string name="preferences_reset_warning">You will lose your settings</string>
<string name="quit">Quit</string>
<string name="quit_reboot">Reset or quit emulator…</string>
<string name="quit_reboot_choice">Reset/reboot or quit?</string>
<string name="quit_reboot_choice">Reset, reboot or quit?&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#13;&#10;</string>
<string name="reboot">Reboot</string>
<string name="reset">Reset</string>
<string name="reset_preferences">Reset settings</string>
@@ -161,7 +166,7 @@
<string name="save">Quick save</string>
<string name="saverestore">Save &amp; restore…</string>
<string name="saverestore_choice">Save current state or restore previous?</string>
<string name="saverestore_summary">Quick save and restore</string>
<string name="saverestore_summary">Save and restore emulator state</string>
<string name="skip">Skip&#8594;</string>
<string name="speaker_volume">Speaker volume</string>
<string name="speaker_volume_summary">Set the speaker volume</string>
@@ -171,9 +176,30 @@
<string name="settings_advanced_joystick">Advanced joystick/keypad settings</string>
<string name="settings_advanced_joystick_summary">Advanced settings and performance tuning</string>
<string name="storage">/storage/</string>
<string name="state_not_restored">Error restoring state…</string>
<string name="touch_menu_enable">Enable touch menus</string>
<string name="touch_menu_enable_summary">Enables soft menu buttons in top screen corners</string>
<string name="video_configure">Configure video…</string>
<string name="video_configure_summary">Color landscape/portrait, color, etc</string>
<string name="video_configure_summary">Landscape/portrait, video modes, colors, etc</string>
<string name="touch_device_color">Configure touch device color</string>
<string name="touch_device_color_summary">Configure color of HUD elements</string>
<string name="touch_device_color_configure">Configure HUD color…</string>
<string name="color_red_on_black">Red on black</string>
<string name="color_green_on_black">Green on black</string>
<string name="color_blue_on_black">Blue on black</string>
<string name="color_white_on_black">White on black</string>
<string name="color_monitor">Color Monitor</string>
<string name="color_tv_mono">Monochrome TV</string>
<string name="color_tv">Color TV</string>
<string name="show_half_scanlines">Show half scanlines</string>
<string name="mono_configure">Monocolor mode</string>
<string name="mono_configure_summary">Configure monochrome color</string>
<string name="color_green">Green screen</string>
<string name="color_mono">Monochrome</string>
<string name="disk_fast_operation">Disk fast loading (EXPERIMENTAL)</string>
<string name="disk_fast_operation_summary">Quickly load disk images (may negatively affect device battery life)</string>
<string name="show_half_scanlines_summary">Renders pixel vertical divisions</string>
<string name="release_notes">Release notes</string>
<string name="release_notes_summary">View notes for this release</string>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>

View File

@@ -0,0 +1,23 @@
[
"Alt keyboard optimized for Ultima(tm) 5",
{
"_comment" : "hex code for special glyphs",
"_AA" : "b5",
"_ESC" : "bc",
"_UP" : "8d",
"_LT" : "88",
"_RT" : "95",
"_DN" : "8a",
"_SP" : "b1"
},
[ "Q", "", "", "", "", "", "", "", "", "" ],
[ "P", "", "", "", "", "", "", "", "", "" ],
["_AA", "", "", "", "", "", "", "", "K", "X"],
[ "N", "", "", "", "", "", "L", "B", "_SP", "V"],
[ "Y", "", "", "", "", "", "Z", "G", "", "_ESC"],
[ "S", "", "", "", "", "", "C", "", "_UP", "" ],
[ "", "", "", "", "", "", "", "_LT", "", "_RT"],
[ "A", "", "T", "O", "J", "F", "E", "", "_DN", ""]
]

View File

@@ -0,0 +1,18 @@
Apple2ix (a2ix) 2.0.0-Android Release Notes
TL;DR : new video mode settings!
CHANGES:
- Implemented a more conformant video scanner. This improves emulation fidelity for programs that implement custom video modes (e.g., custom split screen between text & graphics).
- New NTSC video display modes including "Color monitor", "Monochrome TV", and "Color TV" modes. Thanks to the AppleWin project and Bill Simms for these modes. Also support "Green screen" monochrome video.
- New preference to enable/disable half-scanline video effects.
- EXPERIMENTAL: New preference to enable/disable fast disk image loading. This may cause audio glitches or other instability. Use at your own risk!
GENERAL INFO:
- More information about how to use Apple2ix for Android : https://deadc0de.org/apple2ix/android

View File

@@ -3,9 +3,10 @@
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
classpath 'com.android.tools.build:gradle:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -15,5 +16,6 @@ buildscript {
allprojects {
repositories {
jcenter()
google()
}
}

View File

@@ -1,6 +1,6 @@
#Sun Aug 21 08:35:47 HST 2016
#Mon Nov 12 10:09:47 PST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip

View File

@@ -95,6 +95,8 @@ elif test "$(basename $0)" = "testdisplay" ; then
ln -s testdisplay.mk Android.mk
elif test "$(basename $0)" = "testprefs" ; then
ln -s testprefs.mk Android.mk
elif test "$(basename $0)" = "testtrace" ; then
ln -s testtrace.mk Android.mk
elif test "$(basename $0)" = "testui" ; then
ln -s testui.mk Android.mk
elif test "$(basename $0)" = "testvm" ; then
@@ -123,7 +125,7 @@ if test "x$do_build" = "x1" -o "x$do_release" = "x1" ; then
$CC $CFLAGS -o $apple2_src_path/genfont $apple2_src_path/genfont.c && \
$apple2_src_path/genfont < $apple2_src_path/font.txt > $apple2_src_path/font.c
# trampoline generation
# bridge trampoline generation
TARGET_ARCH=x86 $apple2_src_path/genglue.sh $glue_srcs > $apple2_src_path/x86/glue.S
TARGET_ARCH=arm $apple2_src_path/genglue.sh $glue_srcs > $apple2_src_path/arm/glue.S

View File

@@ -132,7 +132,7 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *en
do {
outputFILE = TEMP_FAILURE_RETRY_FOPEN(fopen(outputPath, "w"));
if (!outputFILE) {
ERRLOG("could not open %s", outputPath);
LOG("could not open %s", outputPath);
break;
}
@@ -146,7 +146,7 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *en
bool success = crashHandler->processCrash(crashPath, symbolsPath, outputFILE);
if (!success) {
RELEASE_LOG("CRASH REPORT PROCESSING FAILED ...");
LOG("CRASH REPORT PROCESSING FAILED ...");
}
} while (0);

View File

@@ -11,6 +11,7 @@
#include "common.h"
#include "androidkeys.h"
#include "json_parse_private.h"
#include <cpu-features.h>
#include <jni.h>
@@ -293,11 +294,11 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass
if (resetState) {
// joystick button settings should be balanced by c_joystick_reset() triggered on CPU thread
if (resetState == 1) {
joy_button0 = 0xff;
joy_button1 = 0x0;
run_args.joy_button0 = 0xff;
run_args.joy_button1 = 0x0;
} else {
joy_button0 = 0x0;
joy_button1 = 0xff;
run_args.joy_button0 = 0x0;
run_args.joy_button1 = 0xff;
}
}
cpu65_interrupt(ResetSig);
@@ -336,7 +337,7 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeOnJoystickMove(JNIEnv *env, jcl
jlong Java_org_deadc0de_apple2ix_Apple2View_nativeOnTouch(JNIEnv *env, jclass cls, jint action, jint pointerCount, jint pointerIndex, jfloatArray xCoords, jfloatArray yCoords) {
//LOG(": %d/%d/%d :", action, pointerCount, pointerIndex);
SCOPE_TRACE_TOUCH("nativeOnTouch");
SCOPE_TRACE_INTERFACE("nativeOnTouch");
if (UNLIKELY(appState != APP_RUNNING)) {
return 0x0LL;
@@ -358,77 +359,239 @@ jlong Java_org_deadc0de_apple2ix_Apple2View_nativeOnTouch(JNIEnv *env, jclass cl
return flags;
}
void Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeChooseDisk(JNIEnv *env, jclass cls, jstring jPath, jboolean driveA, jboolean readOnly) {
jstring Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeChooseDisk(JNIEnv *env, jclass cls, jstring jJsonString) {
#if TESTING
return NULL;
#endif
assert(cpu_isPaused() && "considered dangerous to insert disk image when CPU thread is running");
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
JSON_ref jsonData = NULL;
bool ret = json_createFromString(jsonString, &jsonData);
assert(ret > 0);
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
char *path = NULL;
json_mapCopyStringValue(jsonData, "disk", &path);
json_unescapeSlashes(&path);
assert(path != NULL);
assert(strlen(path) > 0);
bool readOnly = true;
json_mapParseBoolValue(jsonData, "readOnly", &readOnly);
long fd = -1;
if (!json_mapParseLongValue(jsonData, "fd", &fd, 10)) {
TEMP_FAILURE_RETRY(fd = open(path, readOnly ? O_RDONLY : O_RDWR));
if (fd == -1) {
LOG("OOPS could not open disk path : %s", path);
}
} else {
fd = dup(fd);
if (fd == -1) {
LOG("OOPS could not dup file descriptor!");
}
}
long drive = -1;
json_mapParseLongValue(jsonData, "drive", &drive, 10);
assert(drive == 0 || drive == 1);
bool inserted = true;
const char *err = disk6_insert(fd, drive, path, readOnly);
if (err) {
char *diskImageUnreadable = "Disk Image Unreadable";
unsigned int cols = strlen(diskImageUnreadable);
video_getAnimationDriver()->animation_showMessage(diskImageUnreadable, cols, 1);
inserted = false;
} else {
video_getAnimationDriver()->animation_showDiskChosen(drive);
}
json_mapSetBoolValue(jsonData, "inserted", inserted);
if (fd >= 0) {
TEMP_FAILURE_RETRY(close(fd));
fd = -1;
}
if (path) {
FREE(path);
}
jsonString = ((JSON_s *)jsonData)->jsonString;
jstring jstr = (*env)->NewStringUTF(env, jsonString);
json_destroy(&jsonData);
LOG(": (fd:%d, %s, %s, %s)", (int)fd, path, drive ? "drive A" : "drive B", readOnly ? "read only" : "read/write");
return jstr;
}
void Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeEjectDisk(JNIEnv *env, jclass cls, jboolean driveA) {
#if TESTING
return;
#endif
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
int drive = driveA ? 0 : 1;
int ro = readOnly ? 1 : 0;
assert(cpu_isPaused() && "considered dangerous to insert disk image when CPU thread is running");
LOG(": (%s, %s, %s)", path, driveA ? "drive A" : "drive B", readOnly ? "read only" : "read/write");
if (disk6_insert(drive, path, ro)) {
char *gzPath = NULL;
ASPRINTF(&gzPath, "%s.gz", path);
if (disk6_insert(drive, gzPath, ro)) {
char *diskImageUnreadable = "Disk Image Unreadable";
unsigned int cols = strlen(diskImageUnreadable);
video_animations->animation_showMessage(diskImageUnreadable, cols, 1);
} else {
video_animations->animation_showDiskChosen(drive);
}
FREE(gzPath);
} else {
video_animations->animation_showDiskChosen(drive);
}
(*env)->ReleaseStringUTFChars(env, jPath, path);
}
void Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeEjectDisk(JNIEnv *env, jclass cls, jboolean driveA) {
LOG("...");
disk6_eject(!driveA);
disk6_eject(driveA ? 0 : 1);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jclass cls, jstring jPath) {
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
static int _openFdFromJson(OUTPARM int *fdOut, JSON_ref jsonData, const char * const fdKey, const char * const pathKey, int flags, int mode) {
long fd = -1;
char *path = NULL;
do {
if (!json_mapParseLongValue(jsonData, fdKey, &fd, 10)) {
json_mapCopyStringValue(jsonData, pathKey, &path);
assert(path != NULL);
json_unescapeSlashes(&path);
if (strlen(path) <= 0) {
break;
}
if (mode == 0) {
TEMP_FAILURE_RETRY(fd = open(path, flags));
} else {
TEMP_FAILURE_RETRY(fd = open(path, flags, mode));
}
if (fd == -1) {
LOG("OOPS could not open state file path %s", path);
}
} else {
fd = dup(fd);
if (fd == -1) {
LOG("OOPS could not dup file descriptor!");
}
}
} while (0);
FREE(path);
*fdOut = (int)fd;
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jclass cls, jstring jJsonString) {
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
LOG(": (%s)", path);
if (!emulator_saveState(path)) {
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
LOG(": (%s)", jsonString);
JSON_ref jsonData = NULL;
bool ret = json_createFromString(jsonString, &jsonData);
assert(ret > 0);
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
int fdState = -1;
_openFdFromJson(&fdState, jsonData, /*fdKey:*/"fdState", /*pathKey:*/"stateFile", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
if (!emulator_saveState(fdState)) {
LOG("OOPS, could not save emulator state");
}
(*env)->ReleaseStringUTFChars(env, jPath, path);
}
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jclass cls, jstring jPath) {
const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
LOG(": (%s)", path);
if (!emulator_loadState(path)) {
LOG("OOPS, could not load emulator state");
if (fdState >= 0) {
TEMP_FAILURE_RETRY(close(fdState));
fdState = -1;
}
(*env)->ReleaseStringUTFChars(env, jPath, path);
json_destroy(&jsonData);
}
// restoring state may cause a change in disk paths, so we need to notify the Java/Android menu system of the change
// (normally we drive state from the Java/menu side...)
char *disk1 = disk6.disk[0].file_name;
bool readOnly1 = disk6.disk[0].is_protected;
char *disk2 = disk6.disk[1].file_name;
bool readOnly2 = disk6.disk[1].is_protected;
char *str = NULL;
jstring jstr = NULL;
ASPRINTF(&str, "{ disk1 = \"%s\"; readOnly1 = %s; disk2 = \"%s\"; readOnly2 = %s }", (disk1 ?: ""), readOnly1 ? "true" : "false", (disk2 ?: ""), readOnly2 ? "true" : "false");
if (str) {
jstr = (*env)->NewStringUTF(env, str);
FREE(str);
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jclass cls, jstring jJsonString) {
assert(cpu_isPaused() && "considered dangerous to load state when CPU thread is running");
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
LOG(": %s", jsonString);
JSON_ref jsonData = NULL;
int ret = json_createFromString(jsonString, &jsonData);
assert(ret > 0);
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
int fdState = -1;
_openFdFromJson(&fdState, jsonData, /*fdKey:*/"fdState", /*pathKey:*/"stateFile", O_RDONLY, 0);
int fdA = -1;
{
bool readOnlyA = true;
json_mapParseBoolValue(jsonData, "readOnlyA", &readOnlyA);
_openFdFromJson(&fdA, jsonData, /*fdKey:*/"fdA", /*pathKey:*/"diskA", readOnlyA ? O_RDONLY : O_RDWR, 0);
}
int fdB = -1;
{
bool readOnlyB = true;
json_mapParseBoolValue(jsonData, "readOnlyB", &readOnlyB);
_openFdFromJson(&fdB, jsonData, /*fdKey:*/"fdB", /*pathKey:*/"diskB", readOnlyB ? O_RDONLY : O_RDWR, 0);
}
bool loadStateSuccess = true;
if (!emulator_loadState(fdState, (int)fdA, (int)fdB)) {
loadStateSuccess = false;
LOG("OOPS, could not load emulator state");
// FIXME TODO : should show invalid state animation here ...
}
if (fdState >= 0) {
TEMP_FAILURE_RETRY(close(fdState));
fdState = -1;
}
if (fdA >= 0) {
TEMP_FAILURE_RETRY(close(fdA));
fdA = -1;
}
if (fdB >= 0) {
TEMP_FAILURE_RETRY(close(fdB));
fdB = -1;
}
json_mapSetBoolValue(jsonData, "loadStateSuccess", loadStateSuccess);
jsonString = ((JSON_s *)jsonData)->jsonString;
jstring jstr = (*env)->NewStringUTF(env, jsonString);
json_destroy(&jsonData);
return jstr;
}
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeStateExtractDiskPaths(JNIEnv *env, jclass cls, jstring jJsonString) {
assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running");
const char *jsonString = (*env)->GetStringUTFChars(env, jJsonString, NULL);
LOG(": (%s)", jsonString);
JSON_ref jsonData = NULL;
bool ret = json_createFromString(jsonString, &jsonData);
assert(ret > 0);
(*env)->ReleaseStringUTFChars(env, jJsonString, jsonString); jsonString = NULL;
int fdState = -1;
_openFdFromJson(&fdState, jsonData, /*fdKey:*/"fdState", /*pathKey:*/"stateFile", O_RDONLY, 0);
if (!emulator_stateExtractDiskPaths(fdState, jsonData)) {
LOG("OOPS, could not extract disk paths from emulator state file");
}
jsonString = ((JSON_s *)jsonData)->jsonString;
jstring jstr = (*env)->NewStringUTF(env, jsonString);
json_destroy(&jsonData);
if (fdState >= 0) {
TEMP_FAILURE_RETRY(close(fdState));
fdState = -1;
}
return jstr;
@@ -441,9 +604,11 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativePrefsSync(JNIEnv *env, j
domain = (*env)->GetStringUTFChars(env, jDomain, 0);
}
#if !TEST_PREFS
LOG("... domain: %s", domain);
prefs_load();
prefs_sync(domain);
#endif
if (jDomain) {
(*env)->ReleaseStringUTFChars(env, jDomain, domain);

View File

@@ -4,40 +4,64 @@
APPLE2_SRC_PATH := apple2ix-src
APPLE2_X86_SRC := \
$(APPLE2_SRC_PATH)/x86/glue.S $(APPLE2_SRC_PATH)/x86/cpu.S
$(APPLE2_SRC_PATH)/x86/cpu.S \
$(APPLE2_SRC_PATH)/x86/glue.S
APPLE2_ARM_SRC := \
$(APPLE2_SRC_PATH)/arm/glue.S $(APPLE2_SRC_PATH)/arm/cpu.S
$(APPLE2_SRC_PATH)/arm/cpu.S \
$(APPLE2_SRC_PATH)/arm/glue.S
APPLE2_VIDEO_SRC = \
$(APPLE2_SRC_PATH)/video/glvideo.c \
$(APPLE2_SRC_PATH)/video/glnode.c \
$(APPLE2_SRC_PATH)/video/glhudmodel.c \
$(APPLE2_SRC_PATH)/video/glalert.c \
$(APPLE2_SRC_PATH)/video/glhudmodel.c \
$(APPLE2_SRC_PATH)/video/glnode.c \
$(APPLE2_SRC_PATH)/video/gltouchjoy.c \
$(APPLE2_SRC_PATH)/video/gltouchjoy_joy.c \
$(APPLE2_SRC_PATH)/video/gltouchjoy_kpad.c \
$(APPLE2_SRC_PATH)/video/gltouchkbd.c \
$(APPLE2_SRC_PATH)/video/gltouchmenu.c \
$(APPLE2_SRC_PATH)/video/glvideo.c \
$(APPLE2_SRC_PATH)/video/ntsc.c \
$(APPLE2_SRC_PATH)/video/video.c \
$(APPLE2_SRC_PATH)/video_util/matrixUtil.c \
$(APPLE2_SRC_PATH)/video_util/modelUtil.c \
$(APPLE2_SRC_PATH)/video_util/sourceUtil.c \
$(APPLE2_SRC_PATH)/video_util/vectorUtil.c
APPLE2_AUDIO_SRC = \
$(APPLE2_SRC_PATH)/audio/soundcore.c $(APPLE2_SRC_PATH)/audio/soundcore-opensles.c $(APPLE2_SRC_PATH)/audio/speaker.c \
$(APPLE2_SRC_PATH)/audio/mockingboard.c $(APPLE2_SRC_PATH)/audio/AY8910.c
$(APPLE2_SRC_PATH)/audio/AY8910.c \
$(APPLE2_SRC_PATH)/audio/mockingboard.c \
$(APPLE2_SRC_PATH)/audio/soundcore.c \
$(APPLE2_SRC_PATH)/audio/soundcore-opensles.c \
$(APPLE2_SRC_PATH)/audio/speaker.c
APPLE2_META_SRC = \
$(APPLE2_SRC_PATH)/meta/debug.c $(APPLE2_SRC_PATH)/meta/debugger.c $(APPLE2_SRC_PATH)/meta/opcodes.c \
$(APPLE2_SRC_PATH)/meta/lintrace.c $(APPLE2_SRC_PATH)/test/sha1.c $(APPLE2_SRC_PATH)/json_parse.c \
$(APPLE2_SRC_PATH)/memmngt.c $(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c
$(APPLE2_SRC_PATH)/meta/debug.c \
$(APPLE2_SRC_PATH)/meta/debugger.c \
$(APPLE2_SRC_PATH)/meta/systrace.c \
$(APPLE2_SRC_PATH)/meta/log.c \
$(APPLE2_SRC_PATH)/meta/memmngt.c \
$(APPLE2_SRC_PATH)/meta/opcodes.c \
$(APPLE2_SRC_PATH)/test/sha1.c \
APPLE2_MAIN_SRC = \
$(APPLE2_SRC_PATH)/font.c $(APPLE2_SRC_PATH)/rom.c $(APPLE2_SRC_PATH)/misc.c $(APPLE2_SRC_PATH)/display.c $(APPLE2_SRC_PATH)/vm.c \
$(APPLE2_SRC_PATH)/timing.c $(APPLE2_SRC_PATH)/zlib-helpers.c $(APPLE2_SRC_PATH)/joystick.c $(APPLE2_SRC_PATH)/keys.c \
$(APPLE2_SRC_PATH)/interface.c $(APPLE2_SRC_PATH)/disk.c $(APPLE2_SRC_PATH)/cpu-supp.c $(APPLE2_SRC_PATH)/prefs.c \
jnihooks.c androidkeys.c
androidkeys.c \
jnihooks.c \
$(APPLE2_SRC_PATH)/cpu-supp.c \
$(APPLE2_SRC_PATH)/disk.c \
$(APPLE2_SRC_PATH)/display.c \
$(APPLE2_SRC_PATH)/font.c \
$(APPLE2_SRC_PATH)/interface.c \
$(APPLE2_SRC_PATH)/joystick.c \
$(APPLE2_SRC_PATH)/json_parse.c \
$(APPLE2_SRC_PATH)/keys.c \
$(APPLE2_SRC_PATH)/misc.c \
$(APPLE2_SRC_PATH)/prefs.c \
$(APPLE2_SRC_PATH)/rom.c \
$(APPLE2_SRC_PATH)/timing.c \
$(APPLE2_SRC_PATH)/vm.c \
$(APPLE2_SRC_PATH)/zlib-helpers.c \
$(APPLE2_SRC_PATH)/../externals/jsmn/jsmn.c
APPLE2_OPTIM_CFLAGS := -Os
APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -std=gnu11 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)

View File

@@ -23,6 +23,12 @@ else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive

View File

@@ -23,6 +23,12 @@ else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive

View File

@@ -23,6 +23,12 @@ else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive

View File

@@ -23,6 +23,12 @@ else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive

1
Android/jni/testtrace Symbolic link
View File

@@ -0,0 +1 @@
build.sh

40
Android/jni/testtrace.mk Normal file
View File

@@ -0,0 +1,40 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
PACKAGE_IDENTIFIER := "org.deadc0de.apple2ix"
PACKAGE_NAME := "apple2ix"
COMMON_SOURCES_MK := $(LOCAL_PATH)/sources.mk
include $(COMMON_SOURCES_MK)
# -----------------------------------------------------------------------------
# Android build config
LOCAL_MODULE := libapple2ix
LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testtrace.c
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_TRACE=1 -DTESTING=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DSPEAKER_TRACING=1 -DMB_TRACING=1 -I$(APPLE2_SRC_PATH)/test
LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS)
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
LOCAL_CFLAGS += -DNO_UNDERSCORES=1
else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive
include $(BUILD_SHARED_LIBRARY)
# --OR-- Build an executable so native can drive this show
#include $(BUILD_EXECUTABLE)
$(call import-module, android/cpufeatures)

View File

@@ -23,6 +23,12 @@ else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive

View File

@@ -23,6 +23,12 @@ else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
ifeq ($(BUILD_MODE),release)
LOCAL_CFLAGS += -DNDEBUG=1
else
LOCAL_CFLAGS += -g
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC) $(APPLE2_AUDIO_SRC)
# Build a shared library and let Java/Dalvik drive

View File

@@ -677,7 +677,7 @@ log "Found data directory: '$DATA_DIR'"
# is not there, push 'gdbserver' found in prebuilt.
#
DEVICE_GDBSERVER=$DATA_DIR/lib/gdbserver
adb_var_shell2 GDBSERVER_RESULT ls $DEVICE_GDBSERVER
adb_var_shell2 GDBSERVER_RESULT run-as $PACKAGE_NAME ls $DEVICE_GDBSERVER
if [ $? != 0 ]; then
# Figure out what's the target-arch and find gdbserver in prebuilt.

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

View File

@@ -80,9 +80,10 @@
{
cpu_pause();
timing_toggleCPUSpeed();
if (video_animations && video_animations->animation_showCPUSpeed)
video_animation_s *anim = video_getAnimationDriver();
if (anim && anim->animation_showCPUSpeed)
{
video_animations->animation_showCPUSpeed();
anim->animation_showCPUSpeed();
}
cpu_resume();
}
@@ -92,6 +93,7 @@
NSAssert(pthread_main_np(), @"Pause emulation called from non-main thread");
self.paused = !_paused;
}
- (void)setPaused:(BOOL)paused
{
if (_paused == paused)
@@ -102,15 +104,17 @@
_paused = paused;
if (paused)
{
cpu_pause();
cpu_pause();
}
else
{
cpu_resume();
}
if (video_animations && video_animations->animation_showPaused)
video_animation_s *anim = video_getAnimationDriver();
if (anim && anim->animation_showPaused)
{
video_animations->animation_showPaused();
anim->animation_showPaused();
}
}

View File

@@ -56,23 +56,31 @@
{
// This method is triggered whenever the user makes a change to the picker selection.
// The parameter named row and component represents what was selected.
int drive=0;
BOOL ro=YES;
int drive = 0;
BOOL ro = YES;
if(pickerView==self.disk1Picker)
if (pickerView == self.disk1Picker)
{
drive=0;
ro=self.diskAProtection.on;
}
if(pickerView==self.disk2Picker)
if (pickerView == self.disk2Picker)
{
drive=1;
drive=1;
ro=self.diskBProtection.on;
}
NSLog(@"Selected Row %d %@ %c", row,(NSString*)[self._disks objectAtIndex:row],ro);
disk6_eject(drive);
const char *errMsg = disk6_insert(drive, [[self.path stringByAppendingPathComponent:[self._disks objectAtIndex:row]] UTF8String], ro);
const char *path = [[self.path stringByAppendingPathComponent:[self._disks objectAtIndex:row]] UTF8String];
int fd = -1;
TEMP_FAILURE_RETRY(fd = open(path, ro ? O_RDONLY : O_RDWR));
const char *errMsg = disk6_insert(fd, drive, path, ro);
(void)errMsg;
if (fd >= 0) {
TEMP_FAILURE_RETRY(close(fd));
}
}
- (IBAction)unwindToMainViewController:(UIStoryboardSegue*)sender

View File

@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment version="1060" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -373,9 +374,10 @@ CA
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="-608" y="-1487"/>
</menu>
<window title="Apple2Mac" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371" userLabel="Window - Apple2Mac" customClass="EmulatorWindow">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" unifiedTitleAndToolbar="YES"/>
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="200" y="200" width="568" height="384"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
@@ -428,7 +430,7 @@ CA
<toolbarItem reference="85b-WO-tks"/>
</defaultToolbarItems>
</toolbar>
<point key="canvasLocation" x="-308" y="-1288"/>
<point key="canvasLocation" x="-82" y="-1306"/>
</window>
<customObject id="494" userLabel="EmulatorGLView" customClass="EmulatorGLView"/>
<customObject id="M8b-ga-iOS" customClass="EmulatorWindowController" colorLabel="IBBuiltInLabel-Blue">
@@ -472,6 +474,9 @@ CA
<buttonCell key="cell" type="push" title="Choose..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="nVq-kA-8RS">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="chooseDriveA:" target="FHO-g2-V3A" id="aXp-cp-feH"/>
@@ -613,19 +618,13 @@ CA
<action selector="startupDiskBChoiceChanged:" target="FHO-g2-V3A" id="tQS-5l-DDf"/>
</connections>
</button>
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="7ZU-H6-jQn">
<box verticalHuggingPriority="750" boxType="separator" id="7ZU-H6-jQn">
<rect key="frame" x="12" y="59" width="498" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="864-Ov-2tE">
<box horizontalHuggingPriority="750" boxType="separator" id="864-Ov-2tE">
<rect key="frame" x="259" y="70" width="5" height="217"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<button verticalHuggingPriority="750" id="tLd-IJ-Kjl">
<rect key="frame" x="338" y="13" width="85" height="32"/>
@@ -633,9 +632,6 @@ CA
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mSV-MT-MmA">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="disksOK:" target="FHO-g2-V3A" id="8qD-fL-VNb"/>
@@ -643,7 +639,7 @@ DQ
</button>
</subviews>
</view>
<point key="canvasLocation" x="-139" y="-901"/>
<point key="canvasLocation" x="-530" y="-867"/>
</window>
<customObject id="FHO-g2-V3A" customClass="EmulatorDiskController">
<connections>
@@ -656,6 +652,7 @@ DQ
<outlet property="diskInA" destination="cb9-Pc-Ggd" id="chv-2S-Y2R"/>
<outlet property="diskInB" destination="5oU-oN-vUH" id="8fb-s5-EKa"/>
<outlet property="disksWindow" destination="RAk-at-ZT4" id="4wu-vw-EhL"/>
<outlet property="okButton" destination="tLd-IJ-Kjl" id="dvn-gG-jzv"/>
<outlet property="startupLoadDiskA" destination="Ur3-rW-YJG" id="re3-gT-qj3"/>
<outlet property="startupLoadDiskB" destination="Ceo-uO-cRu" id="V0B-0f-YZu"/>
</connections>
@@ -736,12 +733,9 @@ DQ
<action selector="peggedChoiceChanged:" target="mUW-Rh-bL1" id="K2H-Vc-15h"/>
</connections>
</button>
<box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="9U0-v9-wTm">
<box verticalHuggingPriority="750" boxType="separator" id="9U0-v9-wTm">
<rect key="frame" x="17" y="183" width="508" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<slider verticalHuggingPriority="750" id="y10-Rm-oDB">
<rect key="frame" x="15" y="115" width="404" height="27"/>
@@ -780,7 +774,7 @@ DQ
</buttonCell>
<cells>
<column>
<buttonCell type="radio" title="No soundcard" imagePosition="left" alignment="left" enabled="NO" tag="1" inset="2" id="QsT-B1-n2t">
<buttonCell type="radio" title="No soundcard" imagePosition="left" alignment="left" enabled="NO" state="on" tag="1" inset="2" id="QsT-B1-n2t">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@@ -809,12 +803,12 @@ DQ
<popUpButton verticalHuggingPriority="750" id="1sF-py-jCs">
<rect key="frame" x="115" y="271" width="158" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="eVj-ax-48A">
<popUpButtonCell key="cell" type="push" title="Monochrome" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="PX0-X3-MxY" id="eVj-ax-48A">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="gbp-xU-CmX">
<items>
<menuItem title="Black/white" id="PX0-X3-MxY">
<menuItem title="Monochrome" state="on" id="PX0-X3-MxY">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Color" id="TRN-Jh-rFc">
@@ -823,6 +817,15 @@ DQ
<menuItem title="Interpolated" id="RgR-Oe-oo5">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Color Monitor" id="60c-9H-Yr8">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Monochrome TV" id="lQA-Eh-TKs">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Color TV" id="b41-R4-5E3">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
@@ -830,22 +833,8 @@ DQ
<action selector="colorChoiceChanged:" target="mUW-Rh-bL1" id="M58-28-Lmr"/>
</connections>
</popUpButton>
<slider verticalHuggingPriority="750" id="9FG-IJ-hYc">
<rect key="frame" x="115" y="229" width="404" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" enabled="NO" state="on" alignment="left" maxValue="100" doubleValue="50" tickMarkPosition="below" numberOfTickMarks="5" sliderType="linear" id="Cma-o2-8gh"/>
</slider>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="RsU-77-Dkx">
<rect key="frame" x="15" y="241" width="96" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Graphic Effects :" id="foK-d1-Lrb">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="dak-eg-hHn">
<rect key="frame" x="15" y="277" width="96" height="17"/>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" id="dak-eg-hHn">
<rect key="frame" x="15" y="276" width="96" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Color :" id="eHo-1T-edz">
<font key="font" metaFont="system"/>
@@ -853,6 +842,47 @@ DQ
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" id="rDh-8p-gf0">
<rect key="frame" x="15" y="245" width="96" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Monochrome :" id="6zV-cm-vLN">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" misplaced="YES" id="9bP-5g-S3a">
<rect key="frame" x="115" y="240" width="158" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Black/white" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="7Nj-L6-N5K" id="UkC-75-g1J">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="8h0-lQ-adO">
<items>
<menuItem title="Black/white" state="on" id="7Nj-L6-N5K">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Green Screen" id="8Mv-8d-hgV">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="monochromeColorChoiceChanged:" target="mUW-Rh-bL1" id="FIq-tn-pNv"/>
</connections>
</popUpButton>
<button verticalHuggingPriority="750" misplaced="YES" id="0Av-wg-y41">
<rect key="frame" x="115" y="219" width="142" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Show half scanlines" bezelStyle="regularSquare" imagePosition="left" inset="2" id="q9I-GX-oEP">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="scanlinesChoiceChanged:" target="mUW-Rh-bL1" id="7Uf-Tg-ALt"/>
</connections>
</button>
</subviews>
</view>
</tabViewItem>
@@ -861,12 +891,9 @@ DQ
<rect key="frame" x="10" y="33" width="534" height="298"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="Fkg-X3-0XG">
<box horizontalHuggingPriority="750" boxType="separator" id="Fkg-X3-0XG">
<rect key="frame" x="265" y="9" width="5" height="286"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<customView id="OWJ-x7-P0q" customClass="EmulatorJoystickCalibrationView">
<rect key="frame" x="276" y="39" width="256" height="256"/>
@@ -1004,7 +1031,7 @@ DQ
</tabView>
</subviews>
</view>
<point key="canvasLocation" x="-286" y="-1308"/>
<point key="canvasLocation" x="-576" y="-1238"/>
</window>
<customObject id="mUW-Rh-bL1" customClass="EmulatorPrefsController">
<connections>
@@ -1026,18 +1053,20 @@ DQ
<outlet property="joystickStepLabel" destination="ea3-X4-r6a" id="JKX-kB-tcM"/>
<outlet property="joystickStepper" destination="BrH-bm-tx3" id="PmM-yE-XNH"/>
<outlet property="joystickStepperLabel" destination="e2h-SS-aex" id="I6X-YN-AmA"/>
<outlet property="monochromeColorChoice" destination="9bP-5g-S3a" id="dzI-JR-diH"/>
<outlet property="scanlinesChoice" destination="0Av-wg-y41" id="U1V-Re-wVs"/>
<outlet property="soundCardChoice" destination="3d5-Z5-xDN" id="uHI-Ip-s2E"/>
<outlet property="window" destination="Mzv-VG-jce" id="86q-Ys-9Mt"/>
</connections>
</customObject>
</objects>
<resources>
<image name="CPU" width="32" height="32"/>
<image name="Disks" width="32" height="32"/>
<image name="Fullscreen" width="32" height="32"/>
<image name="CPU" width="64" height="64"/>
<image name="Disks" width="64" height="64"/>
<image name="Fullscreen" width="64" height="64"/>
<image name="NSUser" width="32" height="32"/>
<image name="Prefs" width="32" height="32"/>
<image name="Prefs" width="64" height="64"/>
<image name="Reboot" width="32" height="32"/>
<image name="Stop" width="32" height="32"/>
<image name="Stop" width="64" height="64"/>
</resources>
</document>

View File

@@ -34,7 +34,7 @@
[defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed];
[defaults setBool:NO forKey:kApple2CPUSpeedIsMax];
[defaults setBool:NO forKey:kApple2AltSpeedIsMax];
[defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig];
[defaults setInteger:COLOR_MODE_INTERP forKey:kApple2ColorConfig];
// [defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig];
[defaults setBool:YES forKey:kApple2JoystickAutoRecenter];
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
@@ -72,9 +72,9 @@
}
NSInteger mode = [defaults integerForKey:kApple2ColorConfig];
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
if (! ((mode >= COLOR_MODE_BW) && (mode < NUM_COLOROPTS)) )
{
mode = COLOR_NONE;
mode = COLOR_MODE_BW;
}
//[self.videoModePicker d:mode];
//color_mode = (color_mode_t)mode;

View File

@@ -33,9 +33,21 @@
@property (assign) IBOutlet NSButton *chooseDiskB;
@property (assign) IBOutlet NSButton *startupLoadDiskA;
@property (assign) IBOutlet NSButton *startupLoadDiskB;
@property (assign) IBOutlet NSButton *okButton;
- (void)loadPrefsForDomain:(const char *)domain;
@end
static EmulatorDiskController *diskInstance = nil;
static void prefsChangeCallback(const char *domain)
{
(void)domain;
assert(diskInstance);
[diskInstance loadPrefsForDomain:domain];
}
@implementation EmulatorDiskController
- (void)awakeFromNib
@@ -43,7 +55,11 @@
#if CRASH_APP_ON_LOAD_BECAUSE_YAY_GJ_APPLE
glGetError();
#endif
assert(!diskInstance);
diskInstance = self;
prefs_registerListener(PREF_DOMAIN_VM, prefsChangeCallback);
[self.diskInA setStringValue:NO_DISK_INSERTED];
[self.diskAProperties setStringValue:@""];
[self.diskInB setStringValue:NO_DISK_INSERTED];
@@ -52,68 +68,96 @@
[self.chooseDiskA setBezelStyle:NSRoundedBezelStyle];
[self.startupLoadDiskA setState:NSOffState];
[self.startupLoadDiskB setState:NSOffState];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *startupDiskA = [defaults stringForKey:kApple2PrefStartupDiskA];
BOOL readOnlyA = [defaults boolForKey:kApple2PrefStartupDiskAProtected];
if (startupDiskA)
}
- (void)loadPrefsForDomain:(const char *)domain
{
assert(strcmp(domain, PREF_DOMAIN_VM) == 0);
(void)domain;
{
const char *err = disk6_insert(0, [[NSString stringWithFormat:@"%@.gz", startupDiskA] UTF8String], readOnlyA);
if (!err)
NSString *startupDiskA = nil;
char *pathA = NULL;
startupDiskA = prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, &pathA) ? [NSString stringWithUTF8String:pathA] : nil;
FREE(pathA);
bool bVal = false;
BOOL readOnlyA = prefs_parseBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A_RO, &bVal) ? bVal : true;
if (startupDiskA && [startupDiskA length])
{
[self.diskInA setStringValue:[[startupDiskA pathComponents] lastObject]];
[self.startupLoadDiskA setState:NSOnState];
[self.diskAProtection setState:(readOnlyA ? NSOnState : NSOffState) atRow:0 column:0];
[self.diskAProtection setState:(!readOnlyA ? NSOnState : NSOffState) atRow:0 column:1];
const char *path = [startupDiskA UTF8String];
int fdA = -1;
TEMP_FAILURE_RETRY(fdA = open(path, readOnlyA ? O_RDONLY : O_RDWR));
const char *err = disk6_insert(fdA, 0, path, readOnlyA);
if (fdA >= 0) {
TEMP_FAILURE_RETRY(close(fdA));
}
if (!err)
{
[self.diskInA setStringValue:[[startupDiskA pathComponents] lastObject]];
[self.startupLoadDiskA setState:NSOnState];
[self.diskAProtection setState:(readOnlyA ? NSOnState : NSOffState) atRow:0 column:0];
[self.diskAProtection setState:(!readOnlyA ? NSOnState : NSOffState) atRow:0 column:1];
}
}
}
NSString *startupDiskB = [defaults stringForKey:kApple2PrefStartupDiskB];
BOOL readOnlyB = [defaults boolForKey:kApple2PrefStartupDiskBProtected];
if (startupDiskB)
{
const char *err = disk6_insert(1, [[NSString stringWithFormat:@"%@.gz", startupDiskB] UTF8String], readOnlyB);
if (!err)
NSString *startupDiskB = nil;
char *pathB = NULL;
startupDiskB = prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, &pathB) ? [NSString stringWithUTF8String:pathB] : nil;
FREE(pathB);
bool bVal = false;
BOOL readOnlyB = prefs_parseBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B_RO, &bVal) ? bVal : true;
if (startupDiskB && [startupDiskB length])
{
[self.diskInB setStringValue:[[startupDiskB pathComponents] lastObject]];
[self.startupLoadDiskB setState:NSOnState];
[self.diskBProtection setState:(readOnlyB ? NSOnState : NSOffState) atRow:0 column:0];
[self.diskBProtection setState:(!readOnlyB ? NSOnState : NSOffState) atRow:0 column:1];
const char *path = [startupDiskB UTF8String];
int fdB = -1;
TEMP_FAILURE_RETRY(fdB = open(path, readOnlyB ? O_RDONLY : O_RDWR));
const char *err = disk6_insert(fdB, 1, path, readOnlyB);
if (fdB >= 0) {
TEMP_FAILURE_RETRY(close(fdB));
}
if (!err)
{
[self.diskInB setStringValue:[[startupDiskB pathComponents] lastObject]];
[self.startupLoadDiskB setState:NSOnState];
[self.diskBProtection setState:(readOnlyB ? NSOnState : NSOffState) atRow:0 column:0];
[self.diskBProtection setState:(!readOnlyB ? NSOnState : NSOffState) atRow:0 column:1];
}
}
}
}
- (void)_savePrefs
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
[defaults removeObjectForKey:kApple2PrefStartupDiskAProtected];
[defaults removeObjectForKey:kApple2PrefStartupDiskBProtected];
if ([self.startupLoadDiskA state] == NSOnState)
if (([self.startupLoadDiskA state] == NSOnState) && (disk6.disk[0].fd >= 0))
{
if (disk6.disk[0].fd >= 0)
{
NSString *diskA = [NSString stringWithUTF8String:disk6.disk[0].file_name];
[defaults setObject:diskA forKey:kApple2PrefStartupDiskA];
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskAProtection] cells] firstObject];
[defaults setBool:([readOnlyChoice state] == NSOnState) forKey:kApple2PrefStartupDiskAProtected];
}
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, disk6.disk[0].file_name);
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskAProtection] cells] firstObject];
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A_RO, ([readOnlyChoice state] == NSOnState));
}
else
{
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, "");
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A_RO, true);
}
if ([self.startupLoadDiskB state] == NSOnState)
if (([self.startupLoadDiskB state] == NSOnState) && (disk6.disk[1].fd >= 0))
{
if (disk6.disk[1].fd >= 0)
{
NSString *diskB = [NSString stringWithUTF8String:disk6.disk[1].file_name];
[defaults setObject:diskB forKey:kApple2PrefStartupDiskB];
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskBProtection] cells] firstObject];
[defaults setBool:([readOnlyChoice state] == NSOnState) forKey:kApple2PrefStartupDiskBProtected];
}
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, disk6.disk[1].file_name);
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskBProtection] cells] firstObject];
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B_RO, ([readOnlyChoice state] == NSOnState) );
}
else
{
prefs_setStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, "");
prefs_setBoolValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B_RO, true);
}
//prefs_sync(PREF_DOMAIN_VM); -- do not sync here since that will trigger reload of startup disks
prefs_save();
}
- (void)_protectionChangedForDrive:(int)drive
@@ -145,50 +189,65 @@
{
disk6_eject(drive);
const char *errMsg = disk6_insert(drive, [path UTF8String], readOnly);
int fd = -1;
TEMP_FAILURE_RETRY(fd = open([path UTF8String], readOnly ? O_RDONLY : O_RDWR));
const char *errMsg = disk6_insert(fd, drive, [path UTF8String], readOnly);
if (fd >= 0) {
TEMP_FAILURE_RETRY(close(fd));
}
if (errMsg)
{
path = [NSString stringWithFormat:@"%@.gz", path];
errMsg = disk6_insert(drive, [path UTF8String], readOnly);
if (errMsg)
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]];
[alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil];
if (!drive)
{
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]];
[alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil];
if (!drive)
{
[[self diskInA] setStringValue:NO_DISK_INSERTED];
[[self diskAProperties] setStringValue:@""];
}
else
{
[[self diskInB] setStringValue:NO_DISK_INSERTED];
[[self diskBProperties] setStringValue:@""];
}
return NO;
[[self diskInA] setStringValue:NO_DISK_INSERTED];
[[self diskAProperties] setStringValue:@""];
}
else
{
[[self diskInB] setStringValue:NO_DISK_INSERTED];
[[self diskBProperties] setStringValue:@""];
}
return NO;
}
path = [NSString stringWithUTF8String:disk6.disk[drive].file_name];
NSString *imageName = [[path pathComponents] lastObject];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (drive == 0)
{
[[self diskInA] setStringValue:imageName];
if ([[defaults stringForKey:kApple2PrefStartupDiskA] isEqualToString:path])
bool isStartupDiskA = false;
{
char *pathA = NULL;
if (prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_A, &pathA)) {
isStartupDiskA = (strcmp(pathA, disk6.disk[drive].file_name) == 0);
}
FREE(pathA);
}
if (isStartupDiskA)
{
[self.startupLoadDiskA setState:NSOnState];
//[self.diskAProtection setState:(readOnly ? NSOnState : NSOffState) atRow:0 column:0];
//[self.diskAProtection setState:(!readOnly ? NSOnState : NSOffState) atRow:0 column:1];
}
}
else
{
[[self diskInB] setStringValue:imageName];
if ([[defaults stringForKey:kApple2PrefStartupDiskB] isEqualToString:path])
bool isStartupDiskB = false;
{
char *pathB = NULL;
if (prefs_copyStringValue(PREF_DOMAIN_VM, PREF_DISK_PATH_B, &pathB)) {
isStartupDiskB = (strcmp(pathB, disk6.disk[drive].file_name) == 0);
}
FREE(pathB);
}
if (isStartupDiskB)
{
[self.startupLoadDiskB setState:NSOnState];
//[self.diskBProtection setState:(readOnly ? NSOnState : NSOffState) atRow:0 column:0];
//[self.diskBProtection setState:(!readOnly ? NSOnState : NSOffState) atRow:0 column:1];
}
}
@@ -236,7 +295,7 @@
{
extension0 = extension1;
}
return extension0;
return [extension0 lowercaseString];
}
+ (void)chooseDiskForWindow:(NSWindow *)window completionHandler:(DiskCompletionHandler)handler
@@ -288,6 +347,9 @@
return;
}
[self.chooseDiskA setKeyEquivalent:@""];
[self.okButton setKeyEquivalent:@"\r"];
[(drive == 0) ? self.startupLoadDiskA : self.startupLoadDiskB setState:NSOffState];
[self _insertDisketteInDrive:drive path:path type:extension readOnly:readOnly];
}
@@ -318,6 +380,9 @@
- (IBAction)disksOK:(id)sender
{
[self.chooseDiskA setKeyEquivalent:@"\r"];
[self.okButton setKeyEquivalent:@""];
[[self disksWindow] close];
}

View File

@@ -12,7 +12,6 @@
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CVDisplayLink.h>
#import "modelUtil.h"
#import "imageUtil.h"

View File

@@ -37,6 +37,8 @@ const NSString *kDrawTimerNotification = @"kDrawTimerNotification";
@property (nonatomic, retain) NSTimer *timer;
#endif
@property (nonatomic) BOOL prepared;
- (void)initGL;
@end
@@ -166,6 +168,8 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
// Register to be notified when the window closes so we can stop the displaylink
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:[self window]];
self.prepared = true;
}
- (void)windowWillClose:(NSNotification*)notification
@@ -316,6 +320,11 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
// Called during resize operations
// Avoid flickering during resize by drawing
[[self openGLContext] makeCurrentContext];
if (UNLIKELY(!self.prepared)) {
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:@"NSOpenGLView is now deprecated and has a bug ... please restart this app. FIXME TODO : likely we're being forced to move to Metal because Ninjaz and Rockstarz said so :P" code:-1 userInfo:nil]];
[alert beginSheetModalForWindow:[self window] completionHandler:nil];
return;
}
[self drawView];
}
@@ -357,6 +366,8 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)application
{
cpu_pause();
prefs_save();
disk6_eject(0);
disk6_eject(1);
return NSTerminateNow;

View File

@@ -13,4 +13,6 @@
@interface EmulatorJoystickController : NSObject
+ (EmulatorJoystickController *)sharedInstance;
@end

View File

@@ -179,11 +179,11 @@
#endif
// sample buttons only if apple keys aren't pressed. keys get set to 0xff, and js buttons are set to 0x80.
if ((buttonNumber == 0x01) && !(joy_button0 & 0x7f)) {
joy_button0 = 0x80;
if ((buttonNumber == 0x01) && !(run_args.joy_button0 & 0x7f)) {
run_args.joy_button0 = 0x80;
}
if ((buttonNumber == 0x02) && !(joy_button1 & 0x7f)) {
joy_button1 = 0x80;
if ((buttonNumber == 0x02) && !(run_args.joy_button1 & 0x7f)) {
run_args.joy_button1 = 0x80;
}
}
@@ -196,11 +196,11 @@
#endif
// sample buttons only if apple keys aren't pressed. keys get set to 0xff, and js buttons are set to 0x80.
if ((buttonNumber == 0x01) && !(joy_button0 & 0x7f)) {
joy_button0 = 0x0;
if ((buttonNumber == 0x01) && !(run_args.joy_button0 & 0x7f)) {
run_args.joy_button0 = 0x0;
}
if ((buttonNumber == 0x02) && !(joy_button1 & 0x7f)) {
joy_button1 = 0x0;
if ((buttonNumber == 0x02) && !(run_args.joy_button1 & 0x7f)) {
run_args.joy_button1 = 0x0;
}
}

View File

@@ -11,11 +11,6 @@
#import <Cocoa/Cocoa.h>
#define kApple2PrefStartupDiskA @"kApple2PrefStartupDiskA"
#define kApple2PrefStartupDiskAProtected @"kApple2PrefStartupDiskAProtected"
#define kApple2PrefStartupDiskB @"kApple2PrefStartupDiskB"
#define kApple2PrefStartupDiskBProtected @"kApple2PrefStartupDiskBProtected"
@interface EmulatorPrefsController : NSWindowController
@end

View File

@@ -15,18 +15,6 @@
#import "EmulatorWindowController.h"
#import "common.h"
#define kApple2SavedPrefs @"kApple2SavedPrefs"
#define kApple2CPUSpeed @"kApple2CPUSpeed"
#define kApple2CPUSpeedIsMax @"kApple2CPUSpeedIsMax"
#define kApple2AltSpeed @"kApple2AltSpeed"
#define kApple2AltSpeedIsMax @"kApple2AltSpeedIsMax"
#define kApple2SoundcardConfig @"kApple2SoundcardConfig"
#define kApple2ColorConfig @"kApple2ColorConfig"
#define kApple2JoystickConfig @"kApple2JoystickConfig"
#define kApple2JoystickAutoRecenter @"kApple2JoystickAutoRecenter"
#define kApple2JoystickClipToRadius @"kApple2JoystickClipToRadius"
#define kApple2JoystickStep @"kApple2JoystickStep"
@interface EmulatorPrefsController ()
@property (assign) IBOutlet NSSlider *cpuSlider;
@@ -39,6 +27,8 @@
@property (assign) IBOutlet NSMatrix *soundCardChoice;
@property (assign) IBOutlet NSPopUpButton *colorChoice;
@property (assign) IBOutlet NSPopUpButton *monochromeColorChoice;
@property (assign) IBOutlet NSButton *scanlinesChoice;
@property (assign) IBOutlet NSPopUpButton *joystickChoice;
@property (assign) IBOutlet NSButton *joystickRecenter;
@@ -53,34 +43,47 @@
@property (assign) IBOutlet NSTextField *button1Pressed;
@property (assign) IBOutlet EmulatorJoystickCalibrationView *joystickCalibrationView;
- (void)loadPrefsForDomain:(const char *)domain;
@end
static EmulatorPrefsController *prefsInstance = nil;
static void prefsChangeCallback(const char *domain)
{
assert(prefsInstance);
[prefsInstance loadPrefsForDomain:domain];
}
@implementation EmulatorPrefsController
- (void)awakeFromNib
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL firstTime = ![defaults boolForKey:kApple2SavedPrefs];
if (firstTime)
assert(!prefsInstance);
prefsInstance = self;
prefs_registerListener(PREF_DOMAIN_AUDIO, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_INTERFACE, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_JOYSTICK, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_KEYBOARD, prefsChangeCallback);
//prefs_registerListener(PREF_DOMAIN_TOUCHSCREEN, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_VIDEO, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_VM, prefsChangeCallback);
[self _setupJoystickUI];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
}
- (void)loadPrefsForDomain:(const char *)domain
{
domain = NULL; (void)domain;
float fVal, fValDisplay;
fVal = prefs_parseFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, &fVal) ? fVal/100 : 1.0;
fValDisplay = fVal;
if (fVal >= CPU_SCALE_FASTEST)
{
[defaults setBool:YES forKey:kApple2SavedPrefs];
[defaults setDouble:1.0 forKey:kApple2CPUSpeed];
[defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed];
[defaults setBool:NO forKey:kApple2CPUSpeedIsMax];
[defaults setBool:NO forKey:kApple2AltSpeedIsMax];
[defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig];
[defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig];
[defaults setBool:YES forKey:kApple2JoystickAutoRecenter];
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
}
cpu_scale_factor = [defaults doubleForKey:kApple2CPUSpeed];
[self.cpuSlider setDoubleValue:cpu_scale_factor];
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_scale_factor*100]];
if ([defaults boolForKey:kApple2CPUSpeedIsMax])
{
cpu_scale_factor = CPU_SCALE_FASTEST;
fVal = CPU_SCALE_FASTEST;
fValDisplay = CPU_SCALE_FASTEST_PIVOT;
[self.cpuMaxChoice setState:NSOnState];
[self.cpuSlider setEnabled:NO];
}
@@ -89,13 +92,15 @@
[self.cpuMaxChoice setState:NSOffState];
[self.cpuSlider setEnabled:YES];
}
cpu_altscale_factor = [defaults doubleForKey:kApple2AltSpeed];
[self.altSlider setDoubleValue:cpu_altscale_factor];
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_altscale_factor*100]];
if ([defaults boolForKey:kApple2AltSpeedIsMax])
[self.cpuSlider setFloatValue:fVal];
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", fValDisplay*100]];
fVal = prefs_parseFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE_ALT, &fVal) ? fVal/100 : 1.0;
fValDisplay = fVal;
if (fVal >= CPU_SCALE_FASTEST)
{
cpu_altscale_factor = CPU_SCALE_FASTEST;
fVal = CPU_SCALE_FASTEST;
fValDisplay = CPU_SCALE_FASTEST_PIVOT;
[self.altMaxChoice setState:NSOnState];
[self.altSlider setEnabled:NO];
}
@@ -104,50 +109,34 @@
[self.altMaxChoice setState:NSOffState];
[self.altSlider setEnabled:YES];
}
[self.altSlider setFloatValue:fVal];
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", fValDisplay*100]];
#warning TODO : actually implement sound card choices
[self.soundCardChoice deselectAllCells];
[self.soundCardChoice selectCellAtRow:1 column:0];
NSInteger mode = [defaults integerForKey:kApple2ColorConfig];
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
{
mode = COLOR_NONE;
}
[self.colorChoice selectItemAtIndex:mode];
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, (color_mode_t)mode);
prefs_sync(PREF_DOMAIN_VIDEO);
mode = [defaults integerForKey:kApple2JoystickConfig];
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
{
mode = JOY_PCJOY;
}
joy_mode = (joystick_mode_t)mode;
[self.joystickChoice selectItemAtIndex:mode];
long lVal = 0;
NSInteger mode;
mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, &lVal, /*base:*/10) ? getColorMode(lVal) : COLOR_MODE_DEFAULT;
[self.colorChoice selectItemAtIndex:mode];
mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_MONO_MODE, &lVal, /*base:*/10) ? getMonoMode(lVal) : MONO_MODE_DEFAULT;
[self.monochromeColorChoice selectItemAtIndex:mode];
bool bVal = prefs_parseBoolValue(PREF_DOMAIN_VIDEO, PREF_SHOW_HALF_SCANLINES, &bVal) ? bVal : true;
[self.scanlinesChoice setState:bVal ? NSOnState : NSOffState];
[self.joystickChoice selectItemAtIndex:(NSInteger)joy_mode];
#ifdef KEYPAD_JOYSTICK
bool autoRecenter = [defaults integerForKey:kApple2JoystickAutoRecenter];
[self.joystickRecenter setState:autoRecenter ? NSOnState : NSOffState];
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
long joyStep = [defaults integerForKey:kApple2JoystickStep];
if (!joyStep)
{
joyStep = 1;
}
[self.joystickStepLabel setIntegerValue:joyStep];
[self.joystickStepper setIntegerValue:joyStep];
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, joyStep);
prefs_sync(PREF_DOMAIN_JOYSTICK);
[self.joystickRecenter setState:joy_auto_recenter ? NSOnState : NSOffState];
[self.joystickStepLabel setIntegerValue:joy_step];
[self.joystickStepper setIntegerValue:joy_step];
#endif
joy_clip_to_radius = [defaults boolForKey:kApple2JoystickClipToRadius];
[self.joystickClipToRadius setState:joy_clip_to_radius ? NSOnState : NSOffState];
[self _setupJoystickUI];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
}
- (void)dealloc
@@ -156,49 +145,13 @@
[super dealloc];
}
- (void)_savePrefs
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:YES forKey:kApple2SavedPrefs];
[defaults setDouble:cpu_scale_factor forKey:kApple2CPUSpeed];
[defaults setDouble:cpu_altscale_factor forKey:kApple2AltSpeed];
[defaults setBool:([self.cpuMaxChoice state] == NSOnState) forKey:kApple2CPUSpeedIsMax];
[defaults setBool:([self.altMaxChoice state] == NSOnState) forKey:kApple2AltSpeedIsMax];
long lVal = 0;
color_mode_t mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, &lVal, /*base:*/10) ? (color_mode_t)lVal : COLOR_INTERP;
[defaults setInteger:mode forKey:kApple2ColorConfig];
[defaults setInteger:joy_mode forKey:kApple2JoystickConfig];
long joyStep = prefs_parseLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, &lVal, /*base:*/10) ? lVal : 1;
[defaults setInteger:joyStep forKey:kApple2JoystickStep];
bool bVal = false;
bool autoRecenter = prefs_parseBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, &bVal) ? bVal : true;
[defaults setBool:autoRecenter forKey:kApple2JoystickAutoRecenter];
[defaults setBool:joy_clip_to_radius forKey:kApple2JoystickClipToRadius];
prefs_sync(PREF_DOMAIN_JOYSTICK);
}
- (IBAction)sliderDidMove:(id)sender
{
NSSlider *slider = (NSSlider *)sender;
double value = [slider doubleValue];
if (slider == self.cpuSlider)
{
cpu_scale_factor = value;
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
}
else
{
cpu_altscale_factor = value;
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
}
timing_initialize();
[self _savePrefs];
prefs_setFloatValue(PREF_DOMAIN_VM, (slider == self.cpuSlider) ? PREF_CPU_SCALE : PREF_CPU_SCALE_ALT, value*100);
prefs_sync(PREF_DOMAIN_VM);
prefs_save();
}
- (IBAction)peggedChoiceChanged:(id)sender
@@ -206,33 +159,42 @@
NSButton *maxButton = (NSButton *)sender;
if (maxButton == self.cpuMaxChoice)
{
[self.cpuSlider setEnabled:([maxButton state] != NSOnState)];
cpu_scale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
double value = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, value*100);
}
else
{
[self.altSlider setEnabled:([maxButton state] != NSOnState)];
cpu_altscale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
double value = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE_ALT, value*100);
}
timing_initialize();
[self _savePrefs];
prefs_sync(PREF_DOMAIN_VM);
prefs_save();
}
- (IBAction)colorChoiceChanged:(id)sender
{
NSInteger mode = [self.colorChoice indexOfSelectedItem];
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
{
mode = COLOR_NONE;
}
mode = getColorMode(mode);
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, mode);
prefs_sync(PREF_DOMAIN_VIDEO);
[self _savePrefs];
#warning HACK TODO FIXME need to refactor video resetting procedure
video_reset();
prefs_save();
}
- (IBAction)monochromeColorChoiceChanged:(id)sender {
NSInteger mode = [self.monochromeColorChoice indexOfSelectedItem];
mode = getMonoMode(mode);
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_MONO_MODE, mode);
prefs_sync(PREF_DOMAIN_VIDEO);
prefs_save();
}
- (IBAction)scanlinesChoiceChanged:(id)sender
{
NSControlStateValue state = [self.scanlinesChoice state];
prefs_setBoolValue(PREF_DOMAIN_VIDEO, PREF_SHOW_HALF_SCANLINES, state == NSControlStateValueOn);
prefs_sync(PREF_DOMAIN_VIDEO);
prefs_save();
}
- (IBAction)soundCardChoiceChanged:(id)sender
@@ -257,34 +219,35 @@
- (IBAction)joystickChoiceChanged:(id)sender
{
NSInteger mode = [self.joystickChoice indexOfSelectedItem];
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
{
mode = JOY_PCJOY;
}
joy_mode = (joystick_mode_t)mode;
[self _setupJoystickUI];
[self _savePrefs];
mode = getJoyMode(mode);
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_MODE, mode);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
- (IBAction)autoRecenterChoiceChanged:(id)sender
{
bool autoRecenter = ([self.joystickRecenter state] == NSOnState);
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
[self _savePrefs];
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
- (IBAction)clipToRadiusChoiceChanged:(id)sender
{
joy_clip_to_radius = ([self.joystickClipToRadius state] == NSOnState);
[self _savePrefs];
bool clipToRadius = ([self.joystickClipToRadius state] == NSOnState);
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_CLIP_TO_RADIUS, clipToRadius);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
- (IBAction)stepValueChanged:(id)sender
{
long joyStep = [self.joystickStepper intValue];
[self.joystickStepLabel setIntegerValue:joyStep];
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, joyStep);
[self _savePrefs];
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, joyStep);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
#pragma mark -
@@ -295,8 +258,8 @@
if (![self.joystickCalibrationView isHidden])
{
[self.joystickCalibrationView setNeedsDisplay:YES];
[self.button0Pressed setHidden:!(joy_button0)];
[self.button1Pressed setHidden:!(joy_button1)];
[self.button0Pressed setHidden:!(run_args.joy_button0)];
[self.button1Pressed setHidden:!(run_args.joy_button1)];
}
}
@@ -324,8 +287,8 @@
leftAltEngaged = NO;
rightAltEngaged = NO;
}
[self.button0Pressed setHidden:!(joy_button0)];
[self.button1Pressed setHidden:!(joy_button1)];
[self.button0Pressed setHidden:!(run_args.joy_button0)];
[self.button1Pressed setHidden:!(run_args.joy_button1)];
}
- (void)_handleKeyEvent:(NSEvent *)event pressed:(BOOL)pressed

View File

@@ -106,9 +106,10 @@
{
cpu_pause();
timing_toggleCPUSpeed();
if (video_animations && video_animations->animation_showCPUSpeed)
video_animation_s *anim = video_getAnimationDriver();
if (anim && anim->animation_showCPUSpeed)
{
video_animations->animation_showCPUSpeed();
anim->animation_showCPUSpeed();
}
cpu_resume();
}
@@ -141,9 +142,10 @@
[[self pauseItem] setLabel:@"Running"];
cpu_resume();
}
if (video_animations && video_animations->animation_showPaused)
video_animation_s *anim = video_getAnimationDriver();
if (anim && anim->animation_showPaused)
{
video_animations->animation_showPaused();
anim->animation_showPaused();
}
}
@@ -343,6 +345,9 @@
case NSInsertFunctionKey:
scode = SCODE_INS;
break;
case NSDeleteCharacter:
scode = SCODE_L;
break;
case NSDeleteFunctionKey:
scode = SCODE_DEL;
break;

View File

@@ -86,13 +86,13 @@
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
if (error)
{
ERRLOG("Error setting AVAudioSessionCategoryAmbient : %s", [[error description] UTF8String]);
LOG("Error setting AVAudioSessionCategoryAmbient : %s", [[error description] UTF8String]);
error = nil;
}
[[AVAudioSession sharedInstance] setActive:YES error:&error];
if (error)
{
ERRLOG("Error activating AVAudioSession : %s", [[error description] UTF8String]);
LOG("Error activating AVAudioSession : %s", [[error description] UTF8String]);
error = nil;
}
}
@@ -103,7 +103,7 @@
[[AVAudioSession sharedInstance] setActive:NO error:&error];
if (error)
{
ERRLOG("Error deactivating AVAudioSession : %s", [[error description] UTF8String]);
LOG("Error deactivating AVAudioSession : %s", [[error description] UTF8String]);
}
}
@@ -142,14 +142,14 @@
if (error)
{
ERRLOG("Could not create directory. Error: %s", [[error description] UTF8String]);
LOG("Could not create directory. Error: %s", [[error description] UTF8String]);
return;
}
NSArray *fileList = [fileManager contentsOfDirectoryAtPath:resourcesPath error:&error];
if (error)
{
ERRLOG("Could not list contents of bundle. Error: %s", [[error description] UTF8String]);
LOG("Could not list contents of bundle. Error: %s", [[error description] UTF8String]);
return;
}
@@ -174,7 +174,7 @@
[fileManager copyItemAtPath:resourcesFile toPath:documentsFile error:&error];
if (error)
{
ERRLOG("Could not copy file. Error: %s", [[error description] UTF8String]);
LOG("Could not copy file. Error: %s", [[error description] UTF8String]);
}
}
}

View File

@@ -300,25 +300,35 @@ static inline void _handleTouch(EAGLView *self, SEL _cmd, UITouch *touch, interf
// touched menu item ...
if ((flags & TOUCH_FLAGS_INPUT_DEVICE_CHANGE) != 0)
{
video_animation_s *anim = video_getAnimationDriver();
if ((flags & TOUCH_FLAGS_KBD) != 0)
{
//keydriver_setTouchKeyboardOwnsScreen(true);
//joydriver_setTouchJoystickOwnsScreen(false);
video_animations->animation_showTouchKeyboard();
if (anim && anim->animation_showTouchKeyboard)
{
anim->animation_showTouchKeyboard();
}
}
else if ((flags & TOUCH_FLAGS_JOY) != 0)
{
//keydriver_setTouchKeyboardOwnsScreen(false);
//joydriver_setTouchJoystickOwnsScreen(true);
//joydriver_setTouchVariant(EMULATED_JOYSTICK);
video_animations->animation_showTouchJoystick();
if (anim && anim->animation_showTouchKeyboard)
{
anim->animation_showTouchJoystick();
}
}
else if ((flags & TOUCH_FLAGS_JOY_KPAD) != 0)
{
//keydriver_setTouchKeyboardOwnsScreen(false);
//joydriver_setTouchJoystickOwnsScreen(true);
//joydriver_setTouchVariant(EMULATED_KEYPAD);
video_animations->animation_showTouchJoystick();
if (anim && anim->animation_showTouchKeyboard)
{
anim->animation_showTouchJoystick();
}
}
else
{

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
@@ -7,16 +7,16 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.dribin.dave.DDHidLib</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>${CURRENT_MARKETING_VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${CURRENT_MARKETING_VERSION}</string>
</dict>
</plist>

View File

@@ -85,8 +85,8 @@
55D5927D0BAE306E00364849 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 55D5927B0BAE306E00364849 /* InfoPlist.strings */; };
55D592940BAE30B600364849 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 55D592920BAE30B600364849 /* MainMenu.nib */; };
55D593290BAE3ABD00364849 /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
55D593390BAE3ADF00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
55D593660BAE3B5D00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
55D593390BAE3ADF00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
55D593660BAE3B5D00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
55D593750BAE3B7500364849 /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; };
55D5937B0BAE3B8800364849 /* DDHidKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 55CA60E30BA0F2530012CF7B /* DDHidKeyboard.h */; settings = {ATTRIBUTES = (Public, ); }; };
55D5937C0BAE3B8800364849 /* DDHidKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 55CA60E40BA0F2530012CF7B /* DDHidKeyboard.m */; };
@@ -624,7 +624,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0460;
LastUpgradeCheck = 0930;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DDHidLib" */;
compatibilityVersion = "Xcode 3.2";
@@ -831,6 +831,7 @@
551711290B8F420E00C82155 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
@@ -843,6 +844,7 @@
5517112A0B8F420E00C82155 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
@@ -854,6 +856,7 @@
55193E540B93F2EF004C0C98 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -873,6 +876,7 @@
"-framework",
AppKit,
);
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.DDHidLib;
PRODUCT_NAME = DDHidLib;
ZERO_LINK = NO;
};
@@ -881,6 +885,7 @@
55193E550B93F2EF004C0C98 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -898,6 +903,7 @@
"-framework",
AppKit,
);
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.DDHidLib;
PRODUCT_NAME = DDHidLib;
ZERO_LINK = NO;
};
@@ -907,6 +913,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
@@ -923,6 +930,7 @@
"-framework",
AppKit,
);
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDDeviceTest;
PRODUCT_NAME = HIDDeviceTest;
WRAPPER_EXTENSION = app;
};
@@ -932,6 +940,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
@@ -946,6 +955,7 @@
"-framework",
AppKit,
);
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDDeviceTest;
PRODUCT_NAME = HIDDeviceTest;
WRAPPER_EXTENSION = app;
};
@@ -954,6 +964,7 @@
559CBBE70B5B338B00C8FD74 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
@@ -977,6 +988,7 @@
559CBBE80B5B338B00C8FD74 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
@@ -999,6 +1011,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
@@ -1007,6 +1020,7 @@
INFOPLIST_FILE = browser/Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDBrowser;
PRODUCT_NAME = HIDBrowser;
WRAPPER_EXTENSION = app;
ZERO_LINK = NO;
@@ -1017,12 +1031,14 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
buildSettings = {
CLANG_ENABLE_OBJC_WEAK = YES;
COMBINE_HIDPI_IMAGES = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
INFOPLIST_FILE = browser/Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = org.dribin.dave.ddhidlib.HIDBrowser;
PRODUCT_NAME = HIDBrowser;
WRAPPER_EXTENSION = app;
ZERO_LINK = NO;
@@ -1033,12 +1049,37 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
buildSettings = {
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
@@ -1047,10 +1088,33 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7;
SDKROOT = macosx;

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
@@ -9,19 +9,19 @@
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.dribin.dave.ddhidlib.HIDBrowser</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${CURRENT_MARKETING_VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${CURRENT_MARKETING_VERSION}</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
@@ -7,17 +7,17 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.dribin.dave.ddhidlib.HIDDeviceTest</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${CURRENT_MARKETING_VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${CURRENT_MARKETING_VERSION}</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View File

@@ -155,8 +155,7 @@ return retVal;
withClass: (Class) hidClass
skipZeroLocations: (BOOL) skipZeroLocations;
{
(void)((id(*)(id, SEL))objc_msgSend((id)matchDictionary, @selector(retain)));
CFRetain(matchDictionary);
// Now search I/O Registry for matching devices.
io_iterator_t hidObjectIterator = MACH_PORT_NULL;

View File

@@ -53,7 +53,7 @@
- (NSArray *) buttonElements;
- (unsigned) numberOfButtons;
- (NSUInteger) numberOfButtons;
- (void) addElementsToQueue: (DDHidQueue *) queue;

View File

@@ -122,7 +122,7 @@
return mButtonElements;
}
- (unsigned) numberOfButtons;
- (NSUInteger) numberOfButtons;
{
return [mButtonElements count];
}

View File

@@ -24,7 +24,7 @@
#import "DDHidQueue.h"
#import "DDHidElement.h"
#import "DDHIdEvent.h"
#import "DDHidEvent.h"
#import "NSXReturnThrowError.h"
static void queueCallbackFunction(void* target, IOReturn result, void* refcon,

View File

@@ -11,22 +11,29 @@
#if TARGET_OS_IPHONE
# import "AppDelegate.h"
#elif TARGET_OS_MAC
# import <AppKit/NSApplication.h>
#else
# error what new devilry is this?
#endif
extern int argc;
extern const char **argv;
#include "common.h"
int main(int argc_, const char *argv_[])
int main(int argc_, char *argv_[])
{
int retVal = 1;
argc = argc_;
argv = argv_;
#if !TESTING
cpu_pause();
#endif
@autoreleasepool {
#if TARGET_OS_IPHONE
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
#else
retVal = NSApplicationMain(argc, argv);
retVal = NSApplicationMain(argc, (const char **)argv);
#endif
}

View File

@@ -14,13 +14,14 @@ noinst_HEADERS = src/common.h src/cpu.h src/disk.h src/glue.h src/vm.h \
src/timing.h src/uthash.h src/video/video.h src/zlib-helpers.h \
\
src/x86/glue-prologue.h \
src/meta/debug.h src/meta/trace.h \
src/x86/glue-offsets.h src/x86/glue-offsets32.h src/x86/glue-offsets64.h \
src/meta/debug.h src/meta/log.h src/meta/trace.h \
\
src/audio/alhelpers.h src/audio/AY8910.h src/audio/mockingboard.h \
src/audio/peripherals.h src/audio/soundcore.h src/audio/speaker.h \
src/audio/SSI263Phonemes.h
noinst_PROGRAMS = genfont genrom
noinst_PROGRAMS = genfont genrom glue_offsets
###############################################################################
# Apple //ix and supporting sources
@@ -31,12 +32,13 @@ ASM_SRC_x86 = \
src/x86/glue.S src/x86/cpu.S
VIDEO_SRC = \
src/video/xvideo.c \
src/video/glvideo.c \
src/video/glutinput.c \
src/video/glnode.c \
src/video/glhudmodel.c \
src/video/glalert.c \
src/video/ncvideo.c \
src/video/xvideo.c \
src/video_util/matrixUtil.c \
src/video_util/modelUtil.c \
src/video_util/sourceUtil.c \
@@ -46,29 +48,49 @@ AUDIO_SRC = \
src/audio/soundcore.c src/audio/soundcore-openal.c src/audio/speaker.c \
src/audio/playqueue.c src/audio/alhelpers.c src/audio/mockingboard.c \
src/audio/AY8910.c
META_SRC = \
src/meta/debug.l src/meta/debugger.c src/meta/opcodes.c src/test/sha1.c \
src/meta/lintrace.c
# NOTE : selectively enabled through configuration process ...
EXTRA_apple2ix_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
EXTRA_apple2ix_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
apple2ix_SOURCES = src/font.c src/rom.c src/misc.c src/display.c src/vm.c \
src/timing.c src/zlib-helpers.c src/joystick.c src/keys.c src/prefs.c \
src/interface.c src/disk.c src/cpu-supp.c src/json_parse.c src/memmngt.c \
externals/jsmn/jsmn.c
apple2ix_SOURCES = \
externals/jsmn/jsmn.c \
src/cpu-supp.c \
src/disk.c \
src/display.c \
src/font.c \
src/interface.c \
src/joystick.c \
src/json_parse.c \
src/keys.c \
src/meta/darwin-shim.c \
src/meta/debug.l \
src/meta/debugger.c \
src/meta/systrace.c \
src/meta/log.c \
src/meta/memmngt.c \
src/meta/opcodes.c \
src/misc.c \
src/prefs.c \
src/rom.c \
src/test/sha1.c \
src/timing.c \
src/video/video.c \
src/video/ntsc.c \
src/vm.c \
src/zlib-helpers.c
apple2ix_CFLAGS = @AM_CFLAGS@ @X_CFLAGS@
apple2ix_CCASFLAGS = $(apple2ix_CFLAGS)
apple2ix_LDFLAGS = -Wl,-z,noexecstack
apple2ix_LDADD = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@ @X_LIBS@
apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@
apple2ix_LDADD = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @X_LIBS@
apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@
genfont_SOURCES = src/genfont.c
genrom_SOURCES = src/genrom.c
glue_offsets_SOURCES = src/glue-offsets.c
src/font.c: src/font.txt genfont
./genfont < $< > $@
@@ -95,9 +117,9 @@ testcpu_SOURCES = src/test/testcpu.c $(A2_TEST_SOURCES)
testcpu_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_CPU=1
testcpu_CCASFLAGS = $(testcpu_CFLAGS)
testcpu_LDFLAGS = $(apple2ix_LDFLAGS)
testcpu_LDADD = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@ @testcpu_META_O@ @X_LIBS@
testcpu_DEPENDENCIES = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@ @testcpu_META_O@
EXTRA_testcpu_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testcpu_LDADD = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@ @X_LIBS@
testcpu_DEPENDENCIES = @testcpu_ASM_O@ @testcpu_VIDEO_O@ @testcpu_AUDIO_O@
EXTRA_testcpu_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
#######################################
@@ -105,19 +127,19 @@ testdisk_SOURCES = src/test/testdisk.c $(A2_TEST_SOURCES)
testdisk_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_DISK=1 -DDISK_TRACING=1
testdisk_CCASFLAGS = $(testdisk_CFLAGS)
testdisk_LDFLAGS = $(apple2ix_LDFLAGS)
testdisk_LDADD = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@ @testdisk_META_O@ @X_LIBS@
testdisk_DEPENDENCIES = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@ @testdisk_META_O@
EXTRA_testdisk_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testdisk_LDADD = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@ @X_LIBS@
testdisk_DEPENDENCIES = @testdisk_ASM_O@ @testdisk_VIDEO_O@ @testdisk_AUDIO_O@
EXTRA_testdisk_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
#######################################
testdisplay_SOURCES = src/test/testdisplay.c $(A2_TEST_SOURCES)
testdisplay_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_DISPLAY=1
testdisplay_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_DISPLAY=1 -DVIDEO_TRACING=1
testdisplay_CCASFLAGS = $(testdisplay_CFLAGS)
testdisplay_LDFLAGS = $(apple2ix_LDFLAGS)
testdisplay_LDADD = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@ @testdisplay_META_O@ @X_LIBS@
testdisplay_DEPENDENCIES = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@ @testdisplay_META_O@
EXTRA_testdisplay_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testdisplay_LDADD = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@ @X_LIBS@
testdisplay_DEPENDENCIES = @testdisplay_ASM_O@ @testdisplay_VIDEO_O@ @testdisplay_AUDIO_O@
EXTRA_testdisplay_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
#######################################
@@ -125,19 +147,19 @@ testprefs_SOURCES = src/test/testprefs.c $(A2_TEST_SOURCES)
testprefs_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_PREFS=1
testprefs_CCASFLAGS = $(testprefs_CFLAGS)
testprefs_LDFLAGS = $(apple2ix_LDFLAGS)
testprefs_LDADD = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@ @testprefs_META_O@ @X_LIBS@
testprefs_DEPENDENCIES = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@ @testprefs_META_O@
EXTRA_testprefs_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testprefs_LDADD = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@ @X_LIBS@
testprefs_DEPENDENCIES = @testprefs_ASM_O@ @testprefs_VIDEO_O@ @testprefs_AUDIO_O@
EXTRA_testprefs_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
#######################################
testtrace_SOURCES = src/test/testtrace.c $(A2_TEST_SOURCES)
testtrace_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_TRACE=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DVM_TRACING=1 -DSPEAKER_TRACING=1 -DMB_TRACING=1
testtrace_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_TRACE=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DVM_TRACING=1 -DSPEAKER_TRACING=1 -DMB_TRACING=1 -DVIDEO_TRACING=1
testtrace_CCASFLAGS = $(testtrace_CFLAGS)
testtrace_LDFLAGS = $(apple2ix_LDFLAGS)
testtrace_LDADD = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@ @testtrace_META_O@ @X_LIBS@
testtrace_DEPENDENCIES = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@ @testtrace_META_O@
EXTRA_testtrace_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testtrace_LDADD = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@ @X_LIBS@
testtrace_DEPENDENCIES = @testtrace_ASM_O@ @testtrace_VIDEO_O@ @testtrace_AUDIO_O@
EXTRA_testtrace_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
#######################################
@@ -145,9 +167,9 @@ testui_SOURCES = src/test/testui.c $(A2_TEST_SOURCES)
testui_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_UI=1
testui_CCASFLAGS = $(testui_CFLAGS)
testui_LDFLAGS = $(apple2ix_LDFLAGS)
testui_LDADD = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@ @testui_META_O@ @X_LIBS@
testui_DEPENDENCIES = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@ @testui_META_O@
EXTRA_testui_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testui_LDADD = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@ @X_LIBS@
testui_DEPENDENCIES = @testui_ASM_O@ @testui_VIDEO_O@ @testui_AUDIO_O@
EXTRA_testui_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
#######################################
@@ -155,9 +177,9 @@ testvm_SOURCES = src/test/testvm.c $(A2_TEST_SOURCES)
testvm_CFLAGS = $(A2_TEST_CFLAGS) -DTEST_VM=1
testvm_CCASFLAGS = $(testvm_CFLAGS)
testvm_LDFLAGS = $(apple2ix_LDFLAGS)
testvm_LDADD = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@ @testvm_META_O@ @X_LIBS@
testvm_DEPENDENCIES = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@ @testvm_META_O@
EXTRA_testvm_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC) $(META_SRC)
testvm_LDADD = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@ @X_LIBS@
testvm_DEPENDENCIES = @testvm_ASM_O@ @testvm_VIDEO_O@ @testvm_AUDIO_O@
EXTRA_testvm_SOURCES = $(ASM_SRC_x86) $(VIDEO_SRC) $(AUDIO_SRC)
###############################################################################
# Misc & Installation

View File

@@ -10,12 +10,12 @@ Apple2ix derives from the apple2-emul-linux project originally coded by various
The original software was designed to work from the Linux console rendering via SVGAlib. It ran on par to the 1MHz Apple //e on an i386 (Pentium 100 class) or better machine. Later ports added X11 graphics support based on the original X11 DOOM source code drop, ty JC!
As of June 2016, the resurrected Apple2ix runs on x64 MacOSX 10.9+, x64 Debian GNU/Linux, and x86 and ARM Android devices
As of October 2016, the resurrected Apple2ix runs on x86 and ARM Android devices, x64 macOS 10.9+, and x64 GNU/Linux
Project Goals
-------------
* Portability and code resilience across a wide range of modern POSIXy systems including MacOSX, desktop Linux/BSD, iOS, Android. *If you are on Windows, just use the excellent [AppleWin](https://github.com/AppleWin/AppleWin) emulator!*
* Portability and code resilience across a wide range of modern POSIXy systems including macOS, desktop Linux/BSD, iOS, Android. *If you are on Windows, just use the excellent [AppleWin](https://github.com/AppleWin/AppleWin) emulator!*
* Language/platform/API minimalism for core emulation modules (prefer coding to POSIX APIs and using C99 over all other choices)
* Reasonable emulation fidelity to the original Apple //e machine (timing, video, audio, etc...)
* Good platform citizenship for each port (prefer coding in language-of-choice promoted by platform--e.g.: Objective-C/Swift on Darwin, Java on Android, ...)
@@ -31,56 +31,28 @@ Project Tech
* Objective-C and Cocoa APIs (Mac/iOS variant)
* Java and Android APIs (Android app)
Android
-------
Maintained Ports
----------------
* Android 4.0+ (Android Studio & NDK build)
* Desktop GNU/Linux (GNU tools build)
* macOS/iOS (Xcode build)
Published Android App
---------------------
[Available on Google Play](https://play.google.com/store/apps/details?id=org.deadc0de.apple2ix.basic).
Running at 30FPS on ancient Gingerbread (Android 2.3.3) devices:
![Apple2ix on Samsung Galaxy Y running Gingerbread](https://raw.github.com/mauiaaron/apple2/develop/docs/android-galaxyY.png "Apple //ix")
Running at 60FPS on modern Android devices:
Running at 60FPS on Android 4.0+ devices:
![Apple2ix on Nexus 6](https://raw.github.com/mauiaaron/apple2/develop/docs/android-nexus6.png "Apple //ix")
Mac Package
-----------
![Apple2Mac](https://raw.github.com/mauiaaron/apple2/master/docs/Apple2Mac.png "Apple2Mac")
A dated binary package for Macintosh is available at [deadc0de.org](https://deadc0de.org/Apple2Mac/Apple2Mac-0.9.dmg)
Size : 10240000 (10MB)
SHASUM : 81f2d55c2daaa0d3f9b33af9b50f69f6789738bf
Alt Size : 76820480 (75MB)
ALTSUM : 488a40d7f1187bcfd16d0045258f606a95f448cb
Due to Apple's policy about emulators we are unlikely to ship this in the App Store any time soon.
iOS port in progress 2016, check this repo and fork(s) too!
Linux/POSIX
-----------
For Linux and *BSD, I do not personally relish being a package/port maintainer, so you should `./configure --prefix=...`, `make`, `make install` like it's 1999 ;-)
You will need GCC or Clang compiler and other tools as determined by the `configure` script. Use the source!
![Apple //ix](https://raw.github.com/mauiaaron/apple2/master/docs/Apple2ix.png "Apple //ix")
Semi-Ordered TODO
-----------------
* Mockingboard is buggy. Need to research/check upstream (AppleWin and beyond) for bugfixes and refactor.
* Double-LORES graphics (used in Dagen Brock's Flappy Bird clone) are ugly/incorrect ... fix 'em
* Double-HIRES graphics are also ugly/icorrect ... fix 'em
* Improved VBL timing and vSync matching to the device/system refresh rate
* CPU module ports: aarch64, Clang IR (bitcode)
* iOS/iWatch/TVos ports. (iOS in progress 2016)
* Android TV and Android wear
* OpenGL shaders/tricks for style (emulating of various NTSC screen artifacts)
* Emulator save/restore image compatibility with AppleWin
* Emulation features ... (3.5" disk, AppleHD, Phasor, printer, ethernet, ...)
* Debugger rewrite with tests ... improved debugger routines (CLI/curses debugger? GDB/LLDB module?)
* Port to web ... emscripten/asmjs/web assembly
* Emulation feature implementations ... (mouse, printer, 3.5" disk, AppleHD, Phasor, ethernet?, ...)
* OS Ports : Net/Open/Free-BSD ports
* CPU arch ports: aarch64, RISC-V, Clang IR (bitcode)
* Port to web assembly
![DOS 3.3](https://raw.github.com/mauiaaron/apple2/master/docs/DOS33.png "DOS 3.3 Applesoft BASIC and //e monitor")

View File

@@ -1,6 +1,6 @@
dnl ---------------------------------------------------------------------------
AC_DEFINE(PACKAGE_URL, "https://github.com/mauiaaron/apple2", [apple2ix project URL])
AC_DEFINE(PACKAGE_URL, "https://deadc0de.org/apple2ix", [apple2ix project URL])
AC_PREREQ([2.69])
AC_INIT([apple2ix], [0.8])
@@ -92,36 +92,6 @@ AC_SUBST(testvm_ASM_O)
AC_SUBST([AM_CFLAGS])
dnl OS Check
AC_EGREP_CPP(unsupported_, [
#if defined(__ANDROID__)
unsupported_for_now
#elif __APPLE__
unsupported_for_now
#include "TargetConditionals.h"
#if TARGET_OS_SIMULATOR
#elif TARGET_OS_IPHONE
#elif TARGET_OS_MAC
#else
#endif
#elif __linux
linux
#elif __unix
unix
#elif __posix
posix
#else
unknown
#endif
], [
AC_MSG_CHECKING([Operating System ])
AC_MSG_RESULT([unsupported])
AC_MSG_ERROR([Apparently you have an unsupported OS, build aborted])
], [
AC_MSG_CHECKING([Operating System ])
AC_MSG_RESULT([supported])
])
dnl ASM underscore linking test
AC_TRY_LINK([asm("_glibc_foobar:");], [glibc_foobar()], [
AC_MSG_NOTICE([Underscores in assembly linkage allowed...])
@@ -133,6 +103,12 @@ AC_TRY_LINK([asm("_glibc_foobar:");], [glibc_foobar()], [
dnl ---------------------------------------------------------------------------
dnl CLI builds extra search areas ...
CPPFLAGS="$CPPFLAGS -I/opt/local/include"
CFLAGS="$CFLAGS -I/opt/local/include"
CXXFLAGS="$CXXFLAGS -I/opt/local/include"
LDFLAGS="$LDFLAGS -L/opt/local/lib"
# Sometimes Flex is installed as Lex, e.g., NetBSD.
AC_CHECK_PROG([FLEX], [flex lex], [flex])
# Force the use of `missing' to wrap Flex invocations.
@@ -169,76 +145,122 @@ dnl Video ...
AC_PATH_XTRA
opengl_selected='yes'
AC_ARG_ENABLE([opengl], AS_HELP_STRING([--disable-opengl], [Disable OpenGL video driver (uses regular X11)]), [
opengl_selected='no'
], [
video_output="VIDEO RENDERERS:"
video_output_disabled="VIDEO RENDERERS (DISABLED):"
VIDEO_O=""
testcpu_VIDEO_O=""
testdisk_VIDEO_O=""
testdisplay_VIDEO_O=""
testprefs_VIDEO_O=""
testtrace_VIDEO_O=""
testui_VIDEO_O=""
testvm_VIDEO_O=""
AC_ARG_ENABLE([opengl], AS_HELP_STRING([--enable-opengl], [Enable OpenGL graphics output (autodetected)]))
AS_IF([test "x$enable_opengl" != "xno"], [
AC_CHECK_HEADER(GL/glew.h, [
AC_CHECK_HEADER(GL/freeglut.h, [
AC_SEARCH_LIBS(glCreateProgram, [GL], [
AC_SEARCH_LIBS(glutMainLoop, [glut freeglut], [
AC_SEARCH_LIBS(glewInit, [GLEW glew], [
opengl_supported='yes'
AC_DEFINE(VIDEO_OPENGL, 1, [Use OpenGL])
video_output="$video_output OpenGL"
found_opengl="1"
AC_DEFINE(VIDEO_OPENGL, 1, [Building with OpenGL support])
AC_DEFINE(USE_GLUT, 1, [Use GLUT library])
VIDEO_O="src/video/glvideo.o src/video/glnode.o src/video/glalert.o src/video/glhudmodel.o src/video/glutinput.o src/video_util/matrixUtil.o src/video_util/modelUtil.o src/video_util/sourceUtil.o src/video_util/vectorUtil.o"
VIDEO_O="$VIDEO_O src/video/glvideo.o src/video/glnode.o src/video/glalert.o src/video/glhudmodel.o src/video/glutinput.o src/video_util/matrixUtil.o src/video_util/modelUtil.o src/video_util/sourceUtil.o src/video_util/vectorUtil.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_VIDEO_O="src/video/testcpu-glvideo.o src/video/testcpu-glnode.o src/video/testcpu-glalert.o src/video/testcpu-glhudmodel.o src/video/testcpu-glutinput.o src/video_util/testcpu-matrixUtil.o src/video_util/testcpu-modelUtil.o src/video_util/testcpu-sourceUtil.o src/video_util/testcpu-vectorUtil.o"
testdisk_VIDEO_O="src/video/testdisk-glvideo.o src/video/testdisk-glnode.o src/video/testdisk-glalert.o src/video/testdisk-glhudmodel.o src/video/testdisk-glutinput.o src/video_util/testdisk-matrixUtil.o src/video_util/testdisk-modelUtil.o src/video_util/testdisk-sourceUtil.o src/video_util/testdisk-vectorUtil.o"
testdisplay_VIDEO_O="src/video/testdisplay-glvideo.o src/video/testdisplay-glnode.o src/video/testdisplay-glalert.o src/video/testdisplay-glhudmodel.o src/video/testdisplay-glutinput.o src/video_util/testdisplay-matrixUtil.o src/video_util/testdisplay-modelUtil.o src/video_util/testdisplay-sourceUtil.o src/video_util/testdisplay-vectorUtil.o"
testprefs_VIDEO_O="src/video/testprefs-glvideo.o src/video/testprefs-glnode.o src/video/testprefs-glalert.o src/video/testprefs-glhudmodel.o src/video/testprefs-glutinput.o src/video_util/testprefs-matrixUtil.o src/video_util/testprefs-modelUtil.o src/video_util/testprefs-sourceUtil.o src/video_util/testprefs-vectorUtil.o"
testtrace_VIDEO_O="src/video/testtrace-glvideo.o src/video/testtrace-glnode.o src/video/testtrace-glalert.o src/video/testtrace-glhudmodel.o src/video/testtrace-glutinput.o src/video_util/testtrace-matrixUtil.o src/video_util/testtrace-modelUtil.o src/video_util/testtrace-sourceUtil.o src/video_util/testtrace-vectorUtil.o"
testui_VIDEO_O="src/video/testui-glvideo.o src/video/testui-glnode.o src/video/testui-glalert.o src/video/testui-glhudmodel.o src/video/testui-glutinput.o src/video_util/testui-matrixUtil.o src/video_util/testui-modelUtil.o src/video_util/testui-sourceUtil.o src/video_util/testui-vectorUtil.o"
testvm_VIDEO_O="src/video/testvm-glvideo.o src/video/testvm-glnode.o src/video/testvm-glalert.o src/video/testvm-glhudmodel.o src/video/testvm-glutinput.o src/video_util/testvm-matrixUtil.o src/video_util/testvm-modelUtil.o src/video_util/testvm-sourceUtil.o src/video_util/testvm-vectorUtil.o"
AC_MSG_RESULT([Building emulator with OpenGL support, w00t!])
], [
AC_MSG_WARN([Did not find OpenGL GLEW library...])
], [-lGL -lGLEW -lglut])
], [
AC_MSG_WARN([Did not find glut library...])
], [-lGL -lGLEW -lglut])
], [
AC_MSG_WARN([Did not find OpenGL library...])
], [-lGL])
], [
AC_MSG_WARN([Did not find GL/freeglut.h header ...])
testcpu_VIDEO_O="$testcpu_VIDEO_O src/video/testcpu-glvideo.o src/video/testcpu-glnode.o src/video/testcpu-glalert.o src/video/testcpu-glhudmodel.o src/video/testcpu-glutinput.o src/video_util/testcpu-matrixUtil.o src/video_util/testcpu-modelUtil.o src/video_util/testcpu-sourceUtil.o src/video_util/testcpu-vectorUtil.o"
testdisk_VIDEO_O="$testdisk_VIDEO_O src/video/testdisk-glvideo.o src/video/testdisk-glnode.o src/video/testdisk-glalert.o src/video/testdisk-glhudmodel.o src/video/testdisk-glutinput.o src/video_util/testdisk-matrixUtil.o src/video_util/testdisk-modelUtil.o src/video_util/testdisk-sourceUtil.o src/video_util/testdisk-vectorUtil.o"
testdisplay_VIDEO_O="$testdisplay_VIDEO_O src/video/testdisplay-glvideo.o src/video/testdisplay-glnode.o src/video/testdisplay-glalert.o src/video/testdisplay-glhudmodel.o src/video/testdisplay-glutinput.o src/video_util/testdisplay-matrixUtil.o src/video_util/testdisplay-modelUtil.o src/video_util/testdisplay-sourceUtil.o src/video_util/testdisplay-vectorUtil.o"
testprefs_VIDEO_O="$testprefs_VIDEO_O src/video/testprefs-glvideo.o src/video/testprefs-glnode.o src/video/testprefs-glalert.o src/video/testprefs-glhudmodel.o src/video/testprefs-glutinput.o src/video_util/testprefs-matrixUtil.o src/video_util/testprefs-modelUtil.o src/video_util/testprefs-sourceUtil.o src/video_util/testprefs-vectorUtil.o"
testtrace_VIDEO_O="$testtrace_VIDEO_O src/video/testtrace-glvideo.o src/video/testtrace-glnode.o src/video/testtrace-glalert.o src/video/testtrace-glhudmodel.o src/video/testtrace-glutinput.o src/video_util/testtrace-matrixUtil.o src/video_util/testtrace-modelUtil.o src/video_util/testtrace-sourceUtil.o src/video_util/testtrace-vectorUtil.o"
testui_VIDEO_O="$testui_VIDEO_O src/video/testui-glvideo.o src/video/testui-glnode.o src/video/testui-glalert.o src/video/testui-glhudmodel.o src/video/testui-glutinput.o src/video_util/testui-matrixUtil.o src/video_util/testui-modelUtil.o src/video_util/testui-sourceUtil.o src/video_util/testui-vectorUtil.o"
testvm_VIDEO_O="$testvm_VIDEO_O src/video/testvm-glvideo.o src/video/testvm-glnode.o src/video/testvm-glalert.o src/video/testvm-glhudmodel.o src/video/testvm-glutinput.o src/video_util/testvm-matrixUtil.o src/video_util/testvm-modelUtil.o src/video_util/testvm-sourceUtil.o src/video_util/testvm-vectorUtil.o"
AC_MSG_RESULT([configure: NOTE: Building emulator with OpenGL support, w00t!])
], [], [-lGL -lGLEW -lglut])
], [], [-lGL -lGLEW -lglut])
], [], [-lGL])
])
], [
AC_MSG_WARN([Did not find GL/glew.h header ...])
])
AS_IF([test "x$found_opengl" != "x1"], [
AC_MSG_WARN([Did not find OpenGL headers/libraries ... OpenGL support is disabled ...])
video_output_disabled="$video_output_disabled OpenGL"
])
])
AS_IF([test "x$opengl_supported" = "xyes"], [
], [
dnl OpenGL not supported
AS_IF([test "x$opengl_selected" = "xyes"], [
AC_MSG_WARN([!!! DID NOT FIND OPENGL LIBRARIES !!! will attempt to build legacy X11 variant (this is OKAY but LIMITED) ...])
], [])
AC_ARG_ENABLE([x11], AS_HELP_STRING([--enable-x11], [Enable X11 graphics output (autodetected)]))
AS_IF([test "x$enable_x11" != "xno"], [
AC_CHECK_HEADER(X11/XKBlib.h, [
AC_SEARCH_LIBS(XPutImage, [X11], [
found_x11="1"
AC_SEARCH_LIBS(XShmAttach, Xext, [
AC_DEFINE(HAVE_X11_SHM, 1, [Enable X11 MIT SHM extension])
], [
AC_MSG_WARN([Building emulator without support of X11 MITSHM extension...])
], [-lX11])
VIDEO_O="src/video/xvideo.o"
video_output="$video_output X11"
VIDEO_O="$VIDEO_O src/video/xvideo.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_VIDEO_O="src/video/testcpu-xvideo.o"
testdisk_VIDEO_O="src/video/testdisk-xvideo.o"
testdisplay_VIDEO_O="src/video/testdisplay-xvideo.o"
testprefs_VIDEO_O="src/video/testprefs-xvideo.o"
testtrace_VIDEO_O="src/video/testtrace-xvideo.o"
testui_VIDEO_O="src/video/testui-xvideo.o"
testvm_VIDEO_O="src/video/testvm-xvideo.o"
], [
AC_MSG_ERROR([Did not find OpenGL nor X11 libraries...])
], [-LX11])
], [
AC_MSG_ERROR([Did not find OpenGL nor X11 headers...])
testcpu_VIDEO_O="$testcpu_VIDEO_O src/video/testcpu-xvideo.o"
testdisk_VIDEO_O="$testdisk_VIDEO_O src/video/testdisk-xvideo.o"
testdisplay_VIDEO_O="$testdisplay_VIDEO_O src/video/testdisplay-xvideo.o"
testprefs_VIDEO_O="$testprefs_VIDEO_O src/video/testprefs-xvideo.o"
testtrace_VIDEO_O="$testtrace_VIDEO_O src/video/testtrace-xvideo.o"
testui_VIDEO_O="$testui_VIDEO_O src/video/testui-xvideo.o"
testvm_VIDEO_O="$testvm_VIDEO_O src/video/testvm-xvideo.o"
AC_MSG_RESULT([configure: NOTE: Building emulator with X11 support])
], [], [-LX11])
])
AS_IF([test "x$found_x11" != "x1"], [
AC_MSG_WARN([Did not find X11 headers/libraries ... X11 support is disabled ...])
video_output_disabled="$video_output_disabled X11"
])
])
AC_ARG_ENABLE([ncurses], AS_HELP_STRING([--enable-ncurses], [Enable ncurses graphics output (autodetected)]))
AS_IF([test "x$enable_ncurses" != "xno"], [
AC_CHECK_HEADERS(ncurses.h ncursesw/ncurses.h ncurses/ncurses.h ncurses/curses.h curses.h, [
AC_SEARCH_LIBS(initscr, [ncursesw], [
found_ncurses="1"
video_output="$video_output terminal"
VIDEO_O="$VIDEO_O src/video/ncvideo.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_VIDEO_O="$testcpu_VIDEO_O src/video/testcpu-ncvideo.o"
testdisk_VIDEO_O="$testdisk_VIDEO_O src/video/testdisk-ncvideo.o"
testdisplay_VIDEO_O="$testdisplay_VIDEO_O src/video/testdisplay-ncvideo.o"
testprefs_VIDEO_O="$testprefs_VIDEO_O src/video/testprefs-ncvideo.o"
testtrace_VIDEO_O="$testtrace_VIDEO_O src/video/testtrace-ncvideo.o"
testui_VIDEO_O="$testui_VIDEO_O src/video/testui-ncvideo.o"
testvm_VIDEO_O="$testvm_VIDEO_O src/video/testvm-ncvideo.o"
AC_DEFINE(NCURSES_UTF8, 1, [ncurses supports UTF-8])
AC_MSG_RESULT([configure: NOTE: Building emulator with ncurses (UTF-8) support])
], [
AC_SEARCH_LIBS(initscr, [ncurses], [
found_ncurses="1"
video_output="$video_output terminal"
VIDEO_O="$VIDEO_O src/video/ncvideo.o"
testcpu_VIDEO_O="$testcpu_VIDEO_O src/video/testcpu-ncvideo.o"
testdisk_VIDEO_O="$testdisk_VIDEO_O src/video/testdisk-ncvideo.o"
testdisplay_VIDEO_O="$testdisplay_VIDEO_O src/video/testdisplay-ncvideo.o"
testprefs_VIDEO_O="$testprefs_VIDEO_O src/video/testprefs-ncvideo.o"
testtrace_VIDEO_O="$testtrace_VIDEO_O src/video/testtrace-ncvideo.o"
testui_VIDEO_O="$testui_VIDEO_O src/video/testui-ncvideo.o"
testvm_VIDEO_O="$testvm_VIDEO_O src/video/testvm-ncvideo.o"
AC_MSG_RESULT([configure: NOTE: Building emulator with ncurses support])
])
])
break
])
])
AS_IF([test "x$found_ncurses" != "x1"], [
AC_MSG_WARN([Did not find ncurses headers/libraries ... ncurses support is disabled ...])
video_output_disabled="$video_output_disabled terminal"
])
AC_SUBST(VIDEO_O)
AC_SUBST(testcpu_VIDEO_O)
AC_SUBST(testdisk_VIDEO_O)
@@ -248,45 +270,55 @@ AC_SUBST(testtrace_VIDEO_O)
AC_SUBST(testui_VIDEO_O)
AC_SUBST(testvm_VIDEO_O)
dnl ---------------------------------------------------------------------------
dnl Sound ...
openal_selected='yes'
AC_ARG_ENABLE([audio], AS_HELP_STRING([--disable-audio], [Disable emulator audio output]), [
openal_selected='no'
], [
AC_CHECK_HEADER(AL/al.h, [
AC_CHECK_HEADER(AL/alc.h, [
AC_CHECK_HEADER(AL/alext.h, [
AC_SEARCH_LIBS(alcOpenDevice, openal, [
dnl found OpenAL ...
openal_supported='yes'
AUDIO_GLUE_C="src/audio/speaker.c src/audio/mockingboard.c"
AUDIO_O="src/audio/soundcore.o src/audio/soundcore-openal.o src/audio/speaker.o src/audio/playqueue.o src/audio/alhelpers.o src/audio/mockingboard.o src/audio/AY8910.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_AUDIO_O="src/audio/testcpu-soundcore.o src/audio/testcpu-soundcore-openal.o src/audio/testcpu-speaker.o src/audio/testcpu-playqueue.o src/audio/testcpu-alhelpers.o src/audio/testcpu-mockingboard.o src/audio/testcpu-AY8910.o"
testdisk_AUDIO_O="src/audio/testdisk-soundcore.o src/audio/testdisk-soundcore-openal.o src/audio/testdisk-speaker.o src/audio/testdisk-playqueue.o src/audio/testdisk-alhelpers.o src/audio/testdisk-mockingboard.o src/audio/testdisk-AY8910.o"
testdisplay_AUDIO_O="src/audio/testdisplay-soundcore.o src/audio/testdisplay-soundcore-openal.o src/audio/testdisplay-speaker.o src/audio/testdisplay-playqueue.o src/audio/testdisplay-alhelpers.o src/audio/testdisplay-mockingboard.o src/audio/testdisplay-AY8910.o"
testprefs_AUDIO_O="src/audio/testprefs-soundcore.o src/audio/testprefs-soundcore-openal.o src/audio/testprefs-speaker.o src/audio/testprefs-playqueue.o src/audio/testprefs-alhelpers.o src/audio/testprefs-mockingboard.o src/audio/testprefs-AY8910.o"
testtrace_AUDIO_O="src/audio/testtrace-soundcore.o src/audio/testtrace-soundcore-openal.o src/audio/testtrace-speaker.o src/audio/testtrace-playqueue.o src/audio/testtrace-alhelpers.o src/audio/testtrace-mockingboard.o src/audio/testtrace-AY8910.o"
testui_AUDIO_O="src/audio/testui-soundcore.o src/audio/testui-soundcore-openal.o src/audio/testui-speaker.o src/audio/testui-playqueue.o src/audio/testui-alhelpers.o src/audio/testui-mockingboard.o src/audio/testui-AY8910.o"
testvm_AUDIO_O="src/audio/testvm-soundcore.o src/audio/testvm-soundcore-openal.o src/audio/testvm-speaker.o src/audio/testvm-playqueue.o src/audio/testvm-alhelpers.o src/audio/testvm-mockingboard.o src/audio/testvm-AY8910.o"
], [
AC_MSG_ERROR([Could not find OpenAL libraries ... todo fixme ... implement a null sound backend])
], [])
], [
AC_MSG_ERROR([Could not find OpenAL headers ... todo fixme ... implement a null sound backend])
], [
#include <AL/al.h>
#include <AL/alc.h>
AUDIO_GLUE_C="src/audio/speaker.c src/audio/mockingboard.c"
AUDIO_O="src/audio/soundcore.o src/audio/speaker.o src/audio/mockingboard.o src/audio/AY8910.o"
testcpu_AUDIO_O="src/audio/testcpu-soundcore.o src/audio/testcpu-speaker.o src/audio/testcpu-mockingboard.o src/audio/testcpu-AY8910.o"
testdisk_AUDIO_O="src/audio/testdisk-soundcore.o src/audio/testdisk-speaker.o src/audio/testdisk-mockingboard.o src/audio/testdisk-AY8910.o"
testdisplay_AUDIO_O="src/audio/testdisplay-soundcore.o src/audio/testdisplay-speaker.o src/audio/testdisplay-mockingboard.o src/audio/testdisplay-AY8910.o"
testprefs_AUDIO_O="src/audio/testprefs-soundcore.o src/audio/testprefs-speaker.o src/audio/testprefs-mockingboard.o src/audio/testprefs-AY8910.o"
testtrace_AUDIO_O="src/audio/testtrace-soundcore.o src/audio/testtrace-speaker.o src/audio/testtrace-mockingboard.o src/audio/testtrace-AY8910.o"
testui_AUDIO_O="src/audio/testui-soundcore.o src/audio/testui-speaker.o src/audio/testui-mockingboard.o src/audio/testui-AY8910.o"
testvm_AUDIO_O="src/audio/testvm-soundcore.o src/audio/testvm-speaker.o src/audio/testvm-mockingboard.o src/audio/testvm-AY8910.o"
audio_output="AUDIO RENDERERS:"
audio_output_disabled="AUDIO RENDERERS (DISABLED): OpenSLES"
AC_ARG_ENABLE([openal], AS_HELP_STRING([--enable-openal], [Enable OpenAL audio output (autodetected)]))
AS_IF([test "x$enable_openal" != "xno"], [
AC_CHECK_HEADERS(AL/al.h AL/alc.h AL/alext.h, [
AS_IF([test "x$found_openal" != "x1"], [
AC_SEARCH_LIBS(alcOpenDevice, openal, [
found_openal="1"
AUDIO_O="$AUDIO_O src/audio/soundcore-openal.o src/audio/playqueue.o src/audio/alhelpers.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_AUDIO_O="$testcpu_AUDIO_O src/audio/testcpu-soundcore-openal.o src/audio/testcpu-playqueue.o src/audio/testcpu-alhelpers.o"
testdisk_AUDIO_O="$testdisk_AUDIO_O src/audio/testdisk-soundcore-openal.o src/audio/testdisk-playqueue.o src/audio/testdisk-alhelpers.o"
testdisplay_AUDIO_O="$testdisplay_AUDIO_O src/audio/testdisplay-soundcore-openal.o src/audio/testdisplay-playqueue.o src/audio/testdisplay-alhelpers.o"
testprefs_AUDIO_O="$testprefs_AUDIO_O src/audio/testprefs-soundcore-openal.o src/audio/testprefs-playqueue.o src/audio/testprefs-alhelpers.o"
testtrace_AUDIO_O="$testtrace_AUDIO_O src/audio/testtrace-soundcore-openal.o src/audio/testtrace-playqueue.o src/audio/testtrace-alhelpers.o"
testui_AUDIO_O="$testui_AUDIO_O src/audio/testui-soundcore-openal.o src/audio/testui-playqueue.o src/audio/testui-alhelpers.o"
testvm_AUDIO_O="$testvm_AUDIO_O src/audio/testvm-soundcore-openal.o src/audio/testvm-playqueue.o src/audio/testvm-alhelpers.o"
], [], [
dnl -lopenal
])
], [
AC_MSG_ERROR([Could not find OpenAL headers ... todo fixme ... implement a null sound backend])
])
], [
AC_MSG_ERROR([Could not find OpenAL headers ... todo fixme ... implement a null sound backend])
], [
#include <AL/al.h>
#include <AL/alc.h>
])
AS_IF([test "x$found_openal" != "x1"], [
AC_MSG_WARN([Did not find OpenAL headers/libraries ... OpenAL sound output is disabled ...])
audio_output_disabled="$audio_output_disabled OpenAL"
], [
audio_output="$audio_output OpenAL"
])
])
AC_SUBST(AUDIO_GLUE_C)
AC_SUBST(AUDIO_O)
AC_SUBST(testcpu_AUDIO_O)
@@ -297,48 +329,27 @@ AC_SUBST(testtrace_AUDIO_O)
AC_SUBST(testui_AUDIO_O)
AC_SUBST(testvm_AUDIO_O)
AS_IF([test "x$openal_supported" = "xyes"], [
], [
dnl OpenAL not supported
AS_IF([test "x$openal_selected" = "xyes"], [
AC_MSG_WARN([!!! DID NOT FIND OPENAL LIBRARIES !!! audio will be disabled (this is OKAY but LIMITED) ...])
], [])
])
dnl ---------------------------------------------------------------------------
dnl Debugger & classic interface ...
AC_ARG_ENABLE([debugger], AS_HELP_STRING([--disable-debugger], [Disable 6502 debugging console]), [], [
META_O="src/meta/debug.o src/meta/debugger.o src/meta/opcodes.o src/test/sha1.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_META_O="src/meta/testcpu-debug.o src/meta/testcpu-debugger.o src/meta/testcpu-opcodes.o src/test/testcpu-sha1.o"
testdisk_META_O="src/meta/testdisk-debug.o src/meta/testdisk-debugger.o src/meta/testdisk-opcodes.o src/test/testdisk-sha1.o"
testdisplay_META_O="src/meta/testdisplay-debug.o src/meta/testdisplay-debugger.o src/meta/testdisplay-opcodes.o src/test/testdisplay-sha1.o"
testprefs_META_O="src/meta/testprefs-debug.o src/meta/testprefs-debugger.o src/meta/testprefs-opcodes.o src/test/testprefs-sha1.o"
testtrace_META_O="src/meta/testtrace-debug.o src/meta/testtrace-debugger.o src/meta/testtrace-opcodes.o src/test/testtrace-sha1.o"
testui_META_O="src/meta/testui-debug.o src/meta/testui-debugger.o src/meta/testui-opcodes.o src/test/testui-sha1.o"
testvm_META_O="src/meta/testvm-debug.o src/meta/testvm-debugger.o src/meta/testvm-opcodes.o src/test/testvm-sha1.o"
])
AC_SUBST(META_O)
AC_SUBST(testcpu_META_O)
AC_SUBST(testdisk_META_O)
AC_SUBST(testdisplay_META_O)
AC_SUBST(testprefs_META_O)
AC_SUBST(testtrace_META_O)
AC_SUBST(testui_META_O)
AC_SUBST(testvm_META_O)
AC_DEFINE(INTERFACE_CLASSIC, 1, [Use the classic menu interface])
dnl ---------------------------------------------------------------------------
dnl Misc ...
AC_DEFINE(APPLE2IX, 1, [Denotes a section of code as Apple//ix sourced, used with external sources])
AC_DEFINE(INTERFACE_CLASSIC, 1, [Use the classic menu interface])
AC_DEFINE(KEYPAD_JOYSTICK, 1, [Joystick emulated on keyboard ... should not be true on mobile devices])
AC_DEFINE(CONFORMANT_TRACKS, 1, [Conformant to Applewin, and apparently also to the original //e disk timing, but hella-slow on low-end mobile devices])
dnl ---------------------------------------------------------------------------
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
AC_MSG_RESULT([])
AC_MSG_RESULT([Apple //ix emulator A/V configuration:])
AC_MSG_RESULT([ $video_output])
AC_MSG_RESULT([ $audio_output])
AC_MSG_RESULT([])
AC_MSG_RESULT([ $video_output_disabled])
AC_MSG_RESULT([ $audio_output_disabled])
AC_MSG_RESULT([])

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
disks/testdisplay2.dsk.gz Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -13,6 +13,7 @@
#define _CPU_REGS_H_
#include "cpu.h"
#include "glue-offsets.h"
// ARM register mappings
@@ -25,7 +26,7 @@
#define X_Reg r7 /* 8bit 6502 X register */
#define A_Reg r8 /* 8bit 6502 A register */
// r9 is "ARM platform register" ... used as a scratch register
// r10 is another scratch variable
#define reg_args r10 /* cpu65_run() args register */
#define reg_vmem_r r11 /* cpu65_vmem_r table address */
// r12 is "ARM Intra-Procedure-call scratch register" ... used as a scratch register
// r13 ARM SP
@@ -41,7 +42,6 @@
# define ROR_BIT 0x80000000
#endif
#if !defined(__APPLE__)
# define NO_UNDERSCORES 1
# define STRBNE strneb
@@ -57,48 +57,5 @@
# define CALL(x) _##x
#endif
// 2015/11/08 NOTE : Android requires all apps targeting API 23 (AKA Marshmallow) to use Position Independent Code (PIC)
// that does not have TEXT segment relocations
#if !defined(__COUNTER__)
#error __COUNTER__ macro should be available in modern compilers
#endif
#if __PIC__ && !__APPLE__
// 2016/07/15 : TODO FIXME : this PIC code does not work on ARM-Darwin
# define _SYM_ADDR_PRE(reg) \
ldr reg, 5f;
# define _SYM_ADDR_OFF_THUMB(reg,ct) \
4: add reg, pc; \
ldr reg, [reg];
# define _SYM_ADDR_OFF_ARM(reg,ct) \
4: ldr reg, [pc, reg];
# define _SYM_ADDR_POST(var,poff) \
b 6f; \
.align 2; \
5: .word var(GOT_PREL)+(. - (4b + poff)); \
6:
# if defined(THUMB)
# define SYM(reg,var) \
_SYM_ADDR_PRE(reg) \
_SYM_ADDR_OFF_THUMB(reg, __COUNTER__); \
_SYM_ADDR_POST(var,4)
# else
# define SYM(reg,var) \
_SYM_ADDR_PRE(reg) \
_SYM_ADDR_OFF_ARM(reg, __COUNTER__); \
_SYM_ADDR_POST(var,8)
# endif
#else
# if NO_UNDERSCORES
# define SYM(reg,var) \
ldr reg, =var
# else
# define SYM(reg,var) \
ldr reg, =_##var
# endif
#endif
#endif // whole file

View File

@@ -18,46 +18,35 @@
#define DecodeFlags \
SYM(r1, cpu65_flags_decode); \
ldr r1, [reg_args, #CPU65_FLAGS_DECODE]; \
ldrb F_Reg, [r1, r0];
#define EncodeFlags \
SYM(r1, cpu65_flags_encode); \
ldr r1, [reg_args, #CPU65_FLAGS_ENCODE]; \
ldrb r0, [r1, F_Reg];
#define CommonSaveCPUState \
/* save EA */ \
SYM(r0, cpu65_ea); \
strh EffectiveAddr, [r0]; \
strh EffectiveAddr, [reg_args, #CPU65_EA]; \
/* save stack pointer */ \
SYM(r0, cpu65_sp); \
strb SP_Reg, [r0]; \
strb SP_Reg, [reg_args, #CPU65_SP]; \
/* save X */ \
SYM(r0, cpu65_x); \
strb X_Reg, [r0]; \
strb X_Reg, [reg_args, #CPU65_X]; \
/* save Y */ \
SYM(r0, cpu65_y); \
strb Y_Reg, [r0]; \
strb Y_Reg, [reg_args, #CPU65_Y]; \
/* save A */ \
SYM(r0, cpu65_a); \
strb A_Reg, [r0]; \
strb A_Reg, [reg_args, #CPU65_A]; \
/* save flags */ \
EncodeFlags \
SYM(r1, cpu65_f); \
strb r0, [r1]
strb r0, [reg_args, #CPU65_F]
// Tracing is necessary for some CPU tests and to verify operation against other emulators
#if CPU_TRACING
# define TRACE_PROLOGUE \
SYM(r1, cpu65_pc); \
strh PC_Reg, [r1]; \
strh PC_Reg, [reg_args, #CPU65_PC]; \
bl CALL(cpu65_trace_prologue);
# define TRACE_ARG \
bl CALL(cpu65_trace_arg);
# define TRACE_ARG1 \
bl CALL(cpu65_trace_arg1);
# define TRACE_ARG2 \
bl CALL(cpu65_trace_arg2);
# define TRACE_EPILOGUE \
CommonSaveCPUState; \
bl CALL(cpu65_trace_epilogue);
@@ -66,33 +55,26 @@
#else
# define TRACE_PROLOGUE
# define TRACE_ARG
# define TRACE_ARG1
# define TRACE_ARG2
# define TRACE_EPILOGUE
# define TRACE_IRQ
#endif
#define CPUStatsReset \
eor r9, r9, r9; \
SYM(r1, cpu65_opcycles); \
strb r9, [r1]; \
SYM(r1, cpu65_rw); \
strb r9, [r1];
eor r1, r1, r1; \
strb r1, [reg_args, #CPU65_OPCYCLES]; \
strb r1, [reg_args, #CPU65_RW];
#define CPUStatsSetRead \
SYM(r1, cpu65_rw); \
ldrb r9, [r1]; \
orr r9, r9, #1; \
strb r9, [r1];
ldrb r1, [reg_args, #CPU65_RW]; \
orr r1, r1, #1; \
strb r1, [reg_args, #CPU65_RW];
#define CPUStatsSetWrite \
SYM(r1, cpu65_rw); \
ldrb r9, [r1]; \
orr r9, r9, #2; \
strb r9, [r1]; \
SYM(r1, cpu65_d); \
strb r0, [r1];
strb r0, [reg_args, #CPU65_D]; \
ldrb r1, [reg_args, #CPU65_RW]; \
orr r1, r1, #2; \
strb r1, [reg_args, #CPU65_RW];
// ----------------------------------------------------------------------------
// CPU (6502) helper macros
@@ -140,21 +122,20 @@
AddUint16(PC_Reg, #2) \
ldr r1, [reg_vmem_r, EffectiveAddr, LSL PTR_SHIFT]; \
blx r1; \
TRACE_ARG1 \
TRACE_ARG \
mov lo_byte, r0; \
IncUint16(EffectiveAddr) \
ldr r1, [reg_vmem_r, EffectiveAddr, LSL PTR_SHIFT]; \
blx r1; \
TRACE_ARG2; \
TRACE_ARG; \
mov hi_byte, hi_byte, LSL #8; \
orr r0, hi_byte, lo_byte;
#define JumpNextInstruction \
TRACE_PROLOGUE \
GetFromPC_B \
SYM(r1, cpu65_opcode); \
strb r0, [r1]; /* r0 should be next opcode */ \
SYM(r1, cpu65__opcodes); \
strb r0, [reg_args, #CPU65_OPCODE]; /* r0 should be next opcode */ \
ldr r1, [reg_args, #CPU65__OPCODES]; \
ldr r1, [r1, r0, LSL PTR_SHIFT]; \
bx r1;
@@ -175,7 +156,7 @@
#define PutToEA_B \
CPUStatsSetWrite \
SYM(r1, cpu65_vmem_w); \
ldr r1, [reg_args, #CPU65_VMEM_W]; \
ldr r1, [r1, EffectiveAddr, LSL PTR_SHIFT]; \
blx r1;
@@ -197,17 +178,14 @@
mov r0, r0, ASR #24;
#define _IncOpCycles \
SYM(mem_cycle_count, cpu65_opcycles); \
ldrb scratch_count, [mem_cycle_count]; \
ldrb scratch_count, [reg_args, #CPU65_OPCYCLES]; \
add scratch_count, scratch_count, #1;
#define IncOpCycles \
_IncOpCycles \
strb scratch_count, [mem_cycle_count];
strb scratch_count, [reg_args, #CPU65_OPCYCLES];
#define pc_hi_byte r9
#define mem_cycle_count r1
#define scratch_count r12
#define scratch_count r1
#define pc_hi_prev r9
#define pc_hi_next r0
#define BranchXCycles \
@@ -220,7 +198,7 @@
mov pc_hi_next, PC_Reg, LSR #8; \
teq pc_hi_next, pc_hi_prev; \
addne scratch_count, scratch_count, #1; /* +1 branch taken */ \
strb scratch_count, [mem_cycle_count];
strb scratch_count, [reg_args, #CPU65_OPCYCLES];
#define arm_flags r12
#define lahf \
@@ -287,13 +265,12 @@
#define stack_loc r1
#ifdef APPLE2_VM
#define RestoreAltZP \
SYM(stack_loc, base_stackzp); \
ldr stack_loc, [stack_loc]; \
# define RestoreAltZP \
ldr stack_loc, [reg_args, #BASE_STACKZP]; \
add stack_loc, stack_loc, #0x100; \
add stack_loc, stack_loc, SP_Reg;
#else
#define RestoreAltZP
# error FIXME TODO ...
#endif
#define Push(x) \
@@ -1189,8 +1166,7 @@ ENTRY(op_BRK)
EncodeFlags
Push(r0)
orr F_Reg, F_Reg, #I_Flag
SYM(EffectiveAddr, interrupt_vector)
ldrh EffectiveAddr, [EffectiveAddr]
ldrh EffectiveAddr, [reg_args, #INTERRUPT_VECTOR]
GetFromEA_W
mov PC_Reg, r0
Continue
@@ -2406,82 +2382,54 @@ ENTRY(op_WAI_65c02)
#define cycles_exe r0
continue:
SYM(r1, cpu65__opcycles)
SYM(r0, cpu65_opcode)
ldrb r0, [r0]
ldr r1, [reg_args, #CPU65__OPCYCLES]
ldrb r0, [reg_args, #CPU65_OPCODE]
ldrb cycles_exe, [r1, r0]
SYM(r1, cpu65_opcycles)
ldrb r9, [r1]
add cycles_exe, cycles_exe, r9
strb cycles_exe, [r1]
ldrb r1, [reg_args, #CPU65_OPCYCLES]
add cycles_exe, cycles_exe, r1
strb cycles_exe, [reg_args, #CPU65_OPCYCLES]
TRACE_EPILOGUE
SYM(r1, gc_cycles_timer_0)
ldr r9, [r1]
sub r9, r9, cycles_exe
str r9, [r1]
ldr r1, [reg_args, #GC_CYCLES_TIMER_0]
sub r1, r1, cycles_exe
str r1, [reg_args, #GC_CYCLES_TIMER_0]
SYM(r1, gc_cycles_timer_1)
ldr r9, [r1]
sub r9, r9, cycles_exe
str r9, [r1]
ldr r1, [reg_args, #GC_CYCLES_TIMER_1]
sub r1, r1, cycles_exe
str r1, [reg_args, #GC_CYCLES_TIMER_1]
SYM(r1, cpu65_cycle_count)
ldr r9, [r1]
add r9, r9, cycles_exe
str r9, [r1]
ldr r1, [reg_args, #CPU65_CYCLE_COUNT]
add r1, r1, cycles_exe
str r1, [reg_args, #CPU65_CYCLE_COUNT]
#if CONFORMANT_IRQ_CHECKPOINT
SYM(r1, irqCheckTimeout) // AppleWin : CheckInterruptSources()
ldr r9, [r1]
subs r9, r9, cycles_exe
str r9, [r1]
bmi irq_checkpoint
#endif
continue1: SYM(r1, cpu65_cycles_to_execute)
ldr r9, [r1]
subs r9, r9, cycles_exe
str r9, [r1]
continue1: ldr r1, [reg_args, #CPU65_CYCLES_TO_EXECUTE]
subs r1, r1, cycles_exe
str r1, [reg_args, #CPU65_CYCLES_TO_EXECUTE]
bmi exit_cpu65_run
beq exit_cpu65_run
continue2: SYM(r1, cpu65__signal)
ldrb r0, [r1]
continue2: ldrb r0, [reg_args, #CPU65__SIGNAL]
orrs r0, r0, r0
bne exception
CPUStatsReset
JumpNextInstruction
#if CONFORMANT_IRQ_CHECKPOINT
irq_checkpoint:
bl CALL(cpu_irqCheck);
SYM(r1, irqCheckTimeout)
eor r9, r9, r9
str r9, [r1]
b continue1
#endif
/* -------------------------------------------------------------------------
Exception handlers
------------------------------------------------------------------------- */
exception: tst r0, #ResetSig
beq ex_irq
SYM(r1, joy_button0) // OpenApple
ldrb r0, [r1]
ldrb r0, [reg_args, #JOY_BUTTON0] // OpenApple
tst r0, #0xFF
bne exit_reinit
SYM(r1, joy_button1) // ClosedApple
ldrb r0, [r1]
ldr r0, [reg_args, #JOY_BUTTON1] // ClosedApple
tst r0, #0xFF
bne exit_reinit
ex_reset: eor r0, r0, r0
SYM(r1, cpu65__signal)
strb r0, [r1]
SYM(EffectiveAddr, reset_vector)
ldrh EffectiveAddr, [EffectiveAddr]
strb r0, [reg_args, #CPU65__SIGNAL]
ldrh EffectiveAddr, [reg_args, #RESET_VECTOR]
GetFromEA_W
mov PC_Reg, r0
CPUStatsReset
@@ -2502,15 +2450,13 @@ ex_irq: tst F_Reg, #I_Flag // Already interrupt
Push(r0)
orr F_Reg, F_Reg, #BI_Flags
//bic F_Reg, F_Reg, #D_Flag // AppleWin clears Decimal bit?
SYM(EffectiveAddr, interrupt_vector)
ldrh EffectiveAddr, [EffectiveAddr]
ldrh EffectiveAddr, [reg_args, #INTERRUPT_VECTOR]
GetFromEA_W
mov PC_Reg, r0
CPUStatsReset
SYM(r1, cpu65_opcycles)
ldrb r0, [r1]
ldrb r0, [reg_args, #CPU65_OPCYCLES]
add r0, r0, #7 // IRQ handling will take additional 7 cycles
strb r0, [r1]
strb r0, [reg_args, #CPU65_OPCYCLES]
JumpNextInstruction
/* -------------------------------------------------------------------------
@@ -2520,27 +2466,20 @@ ex_irq: tst F_Reg, #I_Flag // Already interrupt
ENTRY(cpu65_run)
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
// Restore CPU state when being called from C.
SYM(reg_vmem_r, cpu65_vmem_r)
SYM(r1, cpu65_ea)
ldrh EffectiveAddr, [r1]
SYM(r1, cpu65_pc)
ldrh PC_Reg, [r1]
SYM(r1, cpu65_a)
ldrb A_Reg, [r1]
SYM(r1, cpu65_f)
ldrb r0, [r1]
mov reg_args, r0
ldr reg_vmem_r, [reg_args, #CPU65_VMEM_R]
ldrh EffectiveAddr, [reg_args, #CPU65_EA]
ldrh PC_Reg, [reg_args, #CPU65_PC]
ldrb A_Reg, [reg_args, #CPU65_A]
ldrb r0, [reg_args, #CPU65_F]
DecodeFlags
SYM(r1, cpu65_x)
ldrb X_Reg, [r1]
SYM(r1, cpu65_y)
ldrb Y_Reg, [r1]
SYM(r1, cpu65_sp)
ldrb SP_Reg, [r1]
SYM(r1, emul_reinitialize)
ldrb r0, [r1]
ldrb X_Reg, [reg_args, #CPU65_X]
ldrb Y_Reg, [reg_args, #CPU65_Y]
ldrb SP_Reg, [reg_args, #CPU65_SP]
ldrb r0, [reg_args, #EMUL_REINITIALIZE]
teq r0, #0
eorne r0, r0, r0
STRBNE r0, [r1]
STRBNE r0, [reg_args, #EMUL_REINITIALIZE]
bne ex_reset
b continue2
@@ -2550,17 +2489,14 @@ ENTRY(cpu65_run)
exit_cpu65_run:
// Save CPU state when returning from being called from C
SYM(r1, cpu65_pc)
strh PC_Reg, [r1]
strh PC_Reg, [reg_args, #CPU65_PC]
CommonSaveCPUState
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
exit_reinit: SYM(r1, cpu65__signal)
mov r0, #0
strb r0, [r1]
SYM(r1, emul_reinitialize)
exit_reinit: mov r0, #0
strb r0, [reg_args, #CPU65__SIGNAL]
mov r0, #1
strb r0, [r1]
strb r0, [reg_args, #EMUL_REINITIALIZE]
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
/* -------------------------------------------------------------------------
@@ -2573,16 +2509,5 @@ ENTRY(cpu65_direct_write)
ldr r0, [r0] // segfault
mov pc, lr
# local data ...
.global interrupt_vector
.global reset_vector
#if NO_UNDERSCORES
interrupt_vector: .hword 0xFFFE
reset_vector: .hword 0xFFFC
#else
_interrupt_vector: .hword 0xFFFE
_reset_vector: .hword 0xFFFC
#endif
.ltorg

5
src/arm/glue-offsets.h Normal file
View File

@@ -0,0 +1,5 @@
#if __aarch64__
# include "glue-offsets64.h"
#else
# include "glue-offsets32.h"
#endif

53
src/arm/glue-offsets32.h Normal file
View File

@@ -0,0 +1,53 @@
/* This file is auto-generated for a specific architecture ABI */
#define UNUSED0 0
#define CPU65_TRACE_PROLOGUE 4
#define CPU65_TRACE_ARG 8
#define UNUSED1 12
#define UNUSED2 16
#define CPU65_TRACE_EPILOGUE 20
#define CPU65_TRACE_IRQ 24
#define DEBUG_ILLEGAL_BCD 28
#define CPU65_VMEM_R 32
#define CPU65_VMEM_W 36
#define CPU65_FLAGS_ENCODE 40
#define CPU65_FLAGS_DECODE 44
#define CPU65__OPCODES 48
#define CPU65__OPCYCLES 52
#define BASE_RAMRD 56
#define BASE_RAMWRT 60
#define BASE_TEXTRD 64
#define BASE_TEXTWRT 68
#define BASE_HGRRD 72
#define BASE_HGRWRT 76
#define BASE_STACKZP 80
#define BASE_D000_RD 84
#define BASE_E000_RD 88
#define BASE_D000_WRT 92
#define BASE_E000_WRT 96
#define BASE_C3ROM 100
#define BASE_C4ROM 104
#define BASE_C5ROM 108
#define BASE_CXROM 112
#define SOFTSWITCHES 116
#define GC_CYCLES_TIMER_0 120
#define GC_CYCLES_TIMER_1 124
#define CPU65_CYCLES_TO_EXECUTE 128
#define CPU65_CYCLE_COUNT 132
#define UNUSED3 136
#define INTERRUPT_VECTOR 140
#define RESET_VECTOR 142
#define CPU65_PC 144
#define CPU65_EA 146
#define CPU65_A 148
#define CPU65_F 149
#define CPU65_X 150
#define CPU65_Y 151
#define CPU65_SP 152
#define CPU65_D 153
#define CPU65_RW 154
#define CPU65_OPCODE 155
#define CPU65_OPCYCLES 156
#define CPU65__SIGNAL 157
#define JOY_BUTTON0 158
#define JOY_BUTTON1 159
#define EMUL_REINITIALIZE 160

View File

@@ -14,70 +14,78 @@
#define GLUE_EXTERN_C_READ(func)
#define GLUE_BANK_MAYBE_READ_CX(func,pointer) \
ENTRY(func) SYM(r1, softswitches); \
ldr r0, [r1]; \
SYM(r1, pointer); \
#define _GLUE_BANK_MAYBE_READ_CX(func,x,pointer) \
ENTRY(func) ldr r0, [reg_args, #SOFTSWITCHES]; \
ldr r1, [reg_args, x ## pointer]; \
tst r0, $SS_CXROM; \
bne 1f; \
push {EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ lr}; \
ldr r1, [r1]; \
push {EffectiveAddr, PC_Reg, lr}; \
blx r1; \
pop {EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ pc}; \
1: ldr r1, [r1]; \
ldrb r0, [r1, EffectiveAddr]; \
pop {EffectiveAddr, PC_Reg, pc}; \
1: ldrb r0, [r1, EffectiveAddr]; \
mov pc, lr;
#define GLUE_BANK_MAYBE_READ_C3(func,pointer) \
ENTRY(func) SYM(r1, softswitches); \
ldr r0, [r1]; \
SYM(r1, pointer); \
#define GLUE_BANK_MAYBE_READ_CX(func,pointer) _GLUE_BANK_MAYBE_READ_CX(func,#,pointer)
#define _GLUE_BANK_MAYBE_READ_C3(func,x,pointer) \
ENTRY(func) ldr r0, [reg_args, #SOFTSWITCHES]; \
ldr r1, [reg_args, x ## pointer]; \
tst r0, $SS_CXROM; \
bne 1f; \
tst r0, $SS_C3ROM; \
bne 1f; \
push {EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ lr}; \
ldr r1, [r1]; \
push {EffectiveAddr, PC_Reg, lr}; \
blx r1; \
pop {EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ pc}; \
1: ldr r1, [r1]; \
pop {EffectiveAddr, PC_Reg, pc}; \
1: ldrb r0, [r1, EffectiveAddr]; \
mov pc, lr;
#define GLUE_BANK_MAYBE_READ_C3(func,pointer) _GLUE_BANK_MAYBE_READ_C3(func,#,pointer)
#define _GLUE_BANK_READ(func,x,pointer) \
ENTRY(func) ldr r1, [reg_args, x ## pointer]; \
ldrb r0, [r1, EffectiveAddr]; \
mov pc, lr;
#define GLUE_BANK_READ(func,pointer) _GLUE_BANK_READ(func,#,pointer)
#define GLUE_BANK_READ(func,pointer) \
ENTRY(func) SYM(r1, pointer); \
ldr r1, [r1]; \
ldrb r0, [r1, EffectiveAddr]; \
mov pc, lr;
#define GLUE_BANK_WRITE(func,pointer) \
ENTRY(func) SYM(r1, pointer); \
ldr r1, [r1]; \
#define _GLUE_BANK_WRITE(func,x,pointer) \
ENTRY(func) ldr r1, [reg_args, x ## pointer]; \
strb r0, [r1, EffectiveAddr]; \
mov pc, lr;
#define GLUE_BANK_WRITE(func,pointer) _GLUE_BANK_WRITE(func,#,pointer)
#define GLUE_BANK_MAYBEWRITE(func,pointer) \
ENTRY(func) SYM(r1, pointer); \
ldr r1, [r1]; \
#define _GLUE_BANK_MAYBEWRITE(func,x,pointer) \
ENTRY(func) ldr r1, [reg_args, x ## pointer]; \
teq r1, #0; \
STRBNE r0, [r1, EffectiveAddr]; \
mov pc, lr;
#define GLUE_BANK_MAYBEWRITE(func,pointer) _GLUE_BANK_MAYBEWRITE(func,#,pointer)
#define _GLUE_INLINE_READ(func,x,off) \
ENTRY(func) ldrb r0, [reg_args, x ## off]; \
mov pc, lr;
#define GLUE_INLINE_READ(func,off) _GLUE_INLINE_READ(func,#,off)
#define GLUE_C_WRITE(func) \
ENTRY(func) push {r0, EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ lr}; \
ENTRY(func) push {r0, EffectiveAddr, PC_Reg, lr}; \
and r0, r0, #0xff; \
mov r1, r0; \
mov r0, EffectiveAddr; \
bl CALL(c_##func); \
pop {r0, EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ pc};
pop {r0, EffectiveAddr, PC_Reg, pc};
#define GLUE_C_READ(func) \
ENTRY(func) push {EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ lr}; \
ENTRY(func) push {EffectiveAddr, PC_Reg, lr}; \
mov r0, EffectiveAddr; \
bl CALL(c_##func); \
pop {EffectiveAddr, PC_Reg, /*SP_Reg, F_Reg, Y_Reg, X_Reg, A_Reg,*/ pc};
pop {EffectiveAddr, PC_Reg, pc};
#define GLUE_C_READ_ALTZP(FUNC) GLUE_C_READ(FUNC)

View File

@@ -52,6 +52,7 @@
# include "audio/mockingboard.h" // For g_uTimer1IrqCount
# if TESTING
# include "greatest.h"
# undef fprintf // greatest redefines fprintf on Droid!
# endif
#endif
@@ -172,7 +173,7 @@ void sound_ay_init( CAY8910 *_this )
_this->ay_env_internal_tick = _this->ay_env_tick = _this->ay_env_period = 0;
_this->ay_tone_subcycles = _this->ay_env_subcycles = 0;
for( f = 0; f < 3; f++ )
_this->ay_tone_tick[f] = _this->ay_tone_high[f] = 0, _this->ay_tone_period[f] = 1;
_this->ay_tone_tick[f] = _this->ay_tone_high[f] = 0; _this->ay_tone_period[f] = 1;
_this->ay_change_count = 0;
}
@@ -236,7 +237,14 @@ static void sound_init( CAY8910 *_this, const char *device, unsigned long nSampl
// sound_generator_freq =
// settings_current.sound_hifi ? HIFI_FREQ : settings_current.sound_freq;
#ifdef APPLE2IX
sound_generator_freq = (int)nSampleRate;
if (UNLIKELY(nSampleRate > INT_MAX)) {
assert(0);
}
#else
sound_generator_freq = nSampleRate;
#endif
sound_generator_framesiz = sound_generator_freq / (int)hz;
#if 0
@@ -364,6 +372,7 @@ sound_unpause( void )
#endif
#if !defined(APPLE2IX)
static void sound_end( CAY8910 *_this )
{
#if 0
@@ -398,6 +407,7 @@ static void sound_end( CAY8910 *_this )
}
#endif
}
#endif
#if 0

View File

@@ -30,7 +30,7 @@ void AY8910_InitAll(int nClock, unsigned long nSampleRate);
void AY8910_InitClock(int nClock, unsigned long nSampleRate);
uint8_t* AY8910_GetRegsPtr(unsigned int uChip);
void AY8910UpdateSetCycles();
void AY8910UpdateSetCycles(void);
#if 1 // APPLE2IX
bool _ay8910_saveState(StateHelper_s *helper, unsigned int chip);

View File

@@ -43,7 +43,7 @@ ALCcontext* InitAL(void)
device = alcOpenDevice(NULL);
if(!device)
{
ERRLOG("Could not open a device!");
LOG("Could not open a device!");
return NULL;
}
@@ -55,7 +55,7 @@ ALCcontext* InitAL(void)
alcDestroyContext(ctx);
}
alcCloseDevice(device);
ERRLOG("Could not set a context!");
LOG("Could not set a context!");
return NULL;
}

View File

@@ -115,7 +115,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# include <sys/io.h>
# endif
# if TESTING
# include "greatest.h"
# include "greatest.h"
# undef fprintf // greatest redefines fprintf on Droid!
# endif
#if defined(FAILED)
@@ -848,7 +849,8 @@ static void SSI263_Write(uint8_t nDevice, uint8_t nReg, uint8_t nValue)
//-------------------------------------
static uint8_t Votrax2SSI263[64] =
#if 0 // ENABLE_SSI263
static uint8_t Votrax2SSI263[64] =
{
0x02, // 00: EH3 jackEt -> E1 bEnt
0x0A, // 01: EH2 Enlist -> EH nEst
@@ -918,6 +920,7 @@ static uint8_t Votrax2SSI263[64] =
0x00, // 3E: PA1 no sound -> PA
0x00, // 3F: STOP no sound -> PA
};
#endif
#if 0 // ENABLE_SSI263
static void Votrax_Write(uint8_t nDevice, uint8_t nValue)
@@ -949,10 +952,11 @@ static void MB_Update()
return;
}
if (!MockingboardVoice->bActive || !g_bMB_Active)
if (!MockingboardVoice->bActive)
{
return;
}
SCOPE_TRACE_AUDIO("MB_Update ...");
# if MB_TRACING
if (mb_trace_fp) {
fprintf(mb_trace_fp, "%s", "\tMB_Update()\n");
@@ -1035,7 +1039,7 @@ static void MB_Update()
unsigned long dwDSLockedBufferSize0 = 0;
int16_t *pDSLockedBuffer0 = NULL;
unsigned long dwCurrentPlayCursor;
int hr = MockingboardVoice->GetCurrentPosition(MockingboardVoice, &dwCurrentPlayCursor);
int hr = (int)MockingboardVoice->GetCurrentPosition(MockingboardVoice, &dwCurrentPlayCursor);
#else
DWORD dwDSLockedBufferSize0, dwDSLockedBufferSize1;
SHORT *pDSLockedBuffer0, *pDSLockedBuffer1;
@@ -1240,6 +1244,7 @@ static void MB_Update()
{
unsigned long modTwo = (dwDSLockedBufferSize0 % 2);
assert(modTwo == 0);
(void)modTwo;
}
memcpy(pDSLockedBuffer0, &g_nMixBuffer[bufIdx/sizeof(short)], dwDSLockedBufferSize0);
MockingboardVoice->Unlock(MockingboardVoice, dwDSLockedBufferSize0);
@@ -1281,7 +1286,8 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
#else
static void* SSI263Thread(void *lpParameter)
{
const unsigned long nsecWait = NANOSECONDS_PER_SECOND / audio_backend->systemSettings.sampleRateHz;
TRACE_AUDIO_MARK("SSI263Thread ...");
const unsigned long nsecWait = NANOSECONDS_PER_SECOND / audio_getCurrentBackend()->systemSettings.sampleRateHz;
const struct timespec wait = { .tv_sec=0, .tv_nsec=nsecWait };
while(1)
@@ -1292,7 +1298,7 @@ static void* SSI263Thread(void *lpParameter)
err = pthread_cond_timedwait(&ssi263_cond, &ssi263_mutex, &wait);
if (err && (err != ETIMEDOUT))
{
ERRLOG("OOPS pthread_cond_timedwait");
LOG("OOPS pthread_cond_timedwait");
}
pthread_mutex_unlock(&ssi263_mutex);
@@ -1502,13 +1508,15 @@ static bool MB_DSInit()
// Create single Mockingboard voice
//
#if 0 // !APPLE2IX
unsigned long dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
int16_t* pDSLockedBuffer;
#endif
if(!audio_isAvailable)
return false;
int hr = audio_createSoundBuffer(&MockingboardVoice);
int hr = (int)audio_createSoundBuffer(&MockingboardVoice);
LOG("MB_DSInit: DSGetSoundBuffer(), hr=0x%08X\n", (unsigned int)hr);
if(FAILED(hr))
{
@@ -1517,13 +1525,13 @@ static bool MB_DSInit()
}
#if 1 // APPLE2IX
SAMPLE_RATE = audio_backend->systemSettings.sampleRateHz;
SAMPLE_RATE = audio_getCurrentBackend()->systemSettings.sampleRateHz;
#if MB_TRACING
// force determinism
SAMPLE_RATE = 44100;
#endif
g_dwDSBufferSize = audio_backend->systemSettings.stereoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample * g_nMB_NumChannels;
g_nMixBuffer = MALLOC(g_dwDSBufferSize / audio_backend->systemSettings.bytesPerSample);
g_dwDSBufferSize = audio_getCurrentBackend()->systemSettings.stereoBufferSizeSamples * audio_getCurrentBackend()->systemSettings.bytesPerSample * g_nMB_NumChannels;
g_nMixBuffer = MALLOC(g_dwDSBufferSize / audio_getCurrentBackend()->systemSettings.bytesPerSample);
#else
bool bRes = DSZeroVoiceBuffer(&MockingboardVoice, "MB", g_dwDSBufferSize);
@@ -1561,12 +1569,12 @@ static bool MB_DSInit()
int err = 0;
if ((err = pthread_mutex_init(&ssi263_mutex, NULL)))
{
ERRLOG("OOPS pthread_mutex_init");
LOG("OOPS pthread_mutex_init");
}
if ((err = pthread_cond_init(&ssi263_cond, NULL)))
{
ERRLOG("OOPS pthread_cond_init");
LOG("OOPS pthread_cond_init");
}
#else
g_hSSI263Event[0] = CreateEvent(NULL, // lpEventAttributes
@@ -1610,14 +1618,14 @@ static bool MB_DSInit()
bPause = false;
}
unsigned int nPhonemeByteLength = g_nPhonemeInfo[nPhoneme].nLength * audio_backend->systemSettings.bytesPerSample;
unsigned int nPhonemeByteLength = g_nPhonemeInfo[nPhoneme].nLength * audio_getCurrentBackend()->systemSettings.bytesPerSample;
#if 0 // !APPLE2IX
// NB. DSBCAPS_LOCSOFTWARE required for Phoneme+2==0x28 - sample too short (see KB327698)
hr = DSGetSoundBuffer(&SSI263Voice[i], DSBCAPS_CTRLVOLUME+DSBCAPS_CTRLPOSITIONNOTIFY+DSBCAPS_LOCSOFTWARE, nPhonemeByteLength, 22050, 1);
LogFileOutput("MB_DSInit: (%02d) DSGetSoundBuffer(), hr=0x%08X\n", i, hr);
#else
if (nPhonemeByteLength > audio_backend->systemSettings.monoBufferSizeSamples) {
RELEASE_ERRLOG("!!!!!!!!!!!!!!!!!!!!! phoneme length > buffer size !!!!!!!!!!!!!!!!!!!!!");
if (nPhonemeByteLength > audio_getCurrentBackend()->systemSettings.monoBufferSizeSamples) {
LOG("!!!!!!!!!!!!!!!!!!!!! phoneme length > buffer size !!!!!!!!!!!!!!!!!!!!!");
#warning ^^^^^^^^^^ require vigilence here around this change ... we used to be able to specify the exact buffer size ...
}
nPhonemeByteLength = dwDSLockedBufferSize;
@@ -1707,7 +1715,7 @@ static bool MB_DSInit()
int err = 0;
if ((err = pthread_create(&g_hThread, NULL, SSI263Thread, NULL)))
{
ERRLOG("SSI263Thread");
LOG("SSI263Thread");
}
// assuming time critical ...
@@ -1718,11 +1726,11 @@ static bool MB_DSInit()
int prio = 0;
if ((prio = sched_get_priority_max(policy)) < 0) {
ERRLOG("OOPS sched_get_priority_max");
LOG("OOPS sched_get_priority_max");
} else {
if ((err = pthread_setschedprio(thread, prio)))
{
ERRLOG("OOPS pthread_setschedprio");
LOG("OOPS pthread_setschedprio");
}
}
# endif
@@ -1756,7 +1764,7 @@ static void MB_DSUninit()
int err = 0;
if ( (err = pthread_join(g_hThread, NULL)) ) {
ERRLOG("OOPS pthread_join");
LOG("OOPS pthread_join");
}
#else
unsigned long dwExitCode;
@@ -1842,7 +1850,7 @@ static void MB_DSUninit()
void MB_Initialize()
{
#if 1 // APPLE2IX
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
memset(SSI263Voice, 0x0, sizeof(AudioBuffer_s *) * 64);
#endif
LOG("MB_Initialize: g_bDisableDirectSound=%d, g_bDisableDirectSoundMockingboard=%d\n", g_bDisableDirectSound, g_bDisableDirectSoundMockingboard);
@@ -1895,11 +1903,11 @@ void MB_Initialize()
#if 1 // APPLE2IX
// HACK functions for "soft" destroying backend audio resource (but keeping current state)
void MB_SoftDestroy(void) {
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
MB_DSUninit();
}
void MB_SoftInitialize(void) {
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
MB_DSInit();
}
#endif
@@ -1922,7 +1930,7 @@ void MB_Reinitialize()
void MB_Destroy()
{
#if 1 // APPLE2IX
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
#endif
MB_DSUninit();
@@ -2191,7 +2199,12 @@ static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
//-----------------------------------------------------------------------------
#if 1 // APPLE2IX
GLUE_C_READ(PhasorIO)
uint8_t c_PhasorIOR (uint16_t);
GLUE_C_WRITE(PhasorIOW)
{
c_PhasorIOR(ea);
}
GLUE_C_READ(PhasorIOR)
#else
static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
#endif
@@ -2230,15 +2243,16 @@ void mb_io_initialize(unsigned int slot4, unsigned int slot5)
}
//typedef uint8_t (*iofunction)(uint16_t nPC, uint16_t nAddr, uint8_t nWriteFlag, uint8_t nWriteValue, unsigned long nCyclesLeft);
typedef void (*iofunction)(void);
static void RegisterIoHandler(unsigned int uSlot, iofunction IOReadC0, iofunction IOWriteC0, iofunction IOReadCx, iofunction IOWriteCx, void *unused_lpSlotParameter, uint8_t* unused_pExpansionRom)
typedef void (*iowfunction)(uint16_t, uint8_t);
typedef uint8_t (*iorfunction)(uint16_t);
static void RegisterIoHandler(unsigned int uSlot, iorfunction IOReadC0, iowfunction IOWriteC0, iorfunction IOReadCx, iowfunction IOWriteCx, void *unused_lpSlotParameter, uint8_t* unused_pExpansionRom)
{
// card softswitches
unsigned int base_addr = 0xC080 + (uSlot<<4); // uSlot == 4 => 0xC0C0 , uSlot == 5 => 0xC0D0
if (IOReadC0)
{
assert(IOWriteC0);
assert((uintptr_t)IOWriteC0);
for (unsigned int i = 0; i < 16; i++)
{
cpu65_vmem_r[base_addr+i] = IOReadC0;
@@ -2271,7 +2285,7 @@ void MB_InitializeIO(char *unused_pCxRomPeripheral, unsigned int uSlot4, unsigne
if (g_Slot4 == CT_MockingboardC)
RegisterIoHandler(uSlot4, IO_Null, IO_Null, MB_Read, MB_Write, NULL, NULL);
else // Phasor
RegisterIoHandler(uSlot4, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
RegisterIoHandler(uSlot4, PhasorIOR, PhasorIOW, MB_Read, MB_Write, NULL, NULL);
if (g_Slot5 == CT_MockingboardC)
RegisterIoHandler(uSlot5, IO_Null, IO_Null, MB_Read, MB_Write, NULL, NULL);
@@ -2356,7 +2370,9 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
if(g_SoundcardType == CT_Empty)
return;
timing_checkpoint_cycles();
SCOPE_TRACE_AUDIO("MB_UpdateCycles");
timing_checkpointCycles();
unsigned long uCycles = cycles_count_total - g_uLastCumulativeCycles;
g_uLastCumulativeCycles = cycles_count_total;
#if MB_TRACING
@@ -2373,6 +2389,9 @@ void MB_UpdateCycles(ULONG uExecutedCycles)
_ASSERT(uCycles < 0x10000);
#endif
uint16_t nClocks = (uint16_t) uCycles;
if (nClocks == 0) {
return;
}
for(int i=0; i<NUM_SY6522; i++)
{

View File

@@ -95,23 +95,23 @@ extern bool g_bMBTimerIrqActive;
extern uint32_t g_uTimer1IrqCount; // DEBUG
#endif
void MB_Initialize();
void MB_Reinitialize();
void MB_Destroy();
void MB_Initialize(void);
void MB_Reinitialize(void);
void MB_Destroy(void);
void MB_SetEnabled(bool enabled);
bool MB_ISEnabled(void);
void MB_Reset();
void MB_Reset(void);
void MB_InitializeIO(char *pCxRomPeripheral, unsigned int uSlot4, unsigned int uSlot5);
void MB_Mute();
void MB_Demute();
void MB_StartOfCpuExecute();
void MB_EndOfVideoFrame();
void MB_Mute(void);
void MB_Demute(void);
void MB_StartOfCpuExecute(void);
void MB_EndOfVideoFrame(void);
void MB_UpdateCycles(void);
SS_CARDTYPE MB_GetSoundcardType();
SS_CARDTYPE MB_GetSoundcardType(void);
void MB_SetSoundcardType(SS_CARDTYPE NewSoundcardType);
double MB_GetFramePeriod();
bool MB_IsActive();
unsigned long MB_GetVolume();
double MB_GetFramePeriod(void);
bool MB_IsActive(void);
unsigned long MB_GetVolume(void);
void MB_SetVolumeZeroToTen(unsigned long goesToTen);
void MB_SetVolume(unsigned long dwVolume, unsigned long dwVolumeMax);
#if 1 // APPLE2IX

View File

@@ -45,7 +45,7 @@ static long playq_enqueue(PlayQueue_s *_this, INOUT PlayNode_s *node) {
// detach a node from the available pool
PQListNode_s *listNode = list->availNodes;
if (!listNode) {
ERRLOG("Cannot enqueue: no slots available");
LOG("Cannot enqueue: no slots available");
err = -1;
break;
}
@@ -220,7 +220,7 @@ void playq_destroyPlayQueue(INOUT PlayQueue_s **queue) {
FREE(*queue);
}
PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffers) {
PlayQueue_s *playq_createPlayQueue(const unsigned int *nodeIdPtr, unsigned long numBuffers) {
PlayQueue_s *playq = NULL;
assert(numBuffers <= MAX_PLAYQ_BUFFERS);
@@ -228,24 +228,24 @@ PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffe
do {
playq = CALLOC(1, sizeof(PlayQueue_s));
if (!playq) {
ERRLOG("no memory");
LOG("no memory");
break;
}
PQList_s *list = CALLOC(1, sizeof(PQList_s));
playq->_internal = list;
if (!list) {
ERRLOG("no memory");
LOG("no memory");
break;
}
bool allocSuccess = true;
for (unsigned long i=0; i<numBuffers; i++) {
PQListNode_s *listNode = CALLOC(1, sizeof(PQListNode_s));
LOG("CREATING PlayNode_s node ID: %ld", nodeIdPtr[i]);
LOG("CREATING PlayNode_s node ID: %u", nodeIdPtr[i]);
listNode->node.nodeId = nodeIdPtr[i];
if (!listNode) {
ERRLOG("no memory");
LOG("no memory");
allocSuccess = false;
break;
}
@@ -277,7 +277,6 @@ PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffe
#define SELF_TEST 0
#if SELF_TEST
bool do_logging = true;
FILE *error_log = NULL;
static void _test_creation(void) {
LOG("begin test");
@@ -789,7 +788,6 @@ static void _test_remove_middle_of_queue(void) {
int main(int argc, char **argv) {
#warning use Valgrind to check proper memory management
error_log = stdout;
LOG("beginning tests");
_test_creation();
_test_internal_list_creation_integrity();

View File

@@ -23,8 +23,8 @@
#define INVALID_NODE_ID INT_MIN
typedef struct PlayNode_s {
long nodeId;
unsigned long numBytes;
unsigned int nodeId;
int numBytes;
uint8_t *bytes;
} PlayNode_s;
@@ -54,7 +54,7 @@ typedef struct PlayQueue_s {
} PlayQueue_s;
// create a play queue object
PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffers);
PlayQueue_s *playq_createPlayQueue(const unsigned int *nodeIdPtr, unsigned long numBuffers);
// destroy a play queue object
void playq_destroyPlayQueue(INOUT PlayQueue_s **queue);

View File

@@ -72,6 +72,7 @@ static AudioBackend_s openal_audio_backend = { { 0 } };
static void _playq_removeNode(ALVoice *voice, PlayNode_s *playNode) {
long err = voice->playq->Remove(voice->playq, playNode);
assert(err == 0);
(void)err;
voice->_queued_total_bytes -= playNode->numBytes;
assert(voice->_queued_total_bytes >= 0);
}
@@ -84,7 +85,7 @@ static long _ALProcessPlayBuffers(ALVoice *voice, ALuint *bytes_queued) {
ALint processed = 0;
alGetSourcei(voice->source, AL_BUFFERS_PROCESSED, &processed);
if ((err = alGetError()) != AL_NO_ERROR) {
ERRLOG("OOPS, error in checking processed buffers : 0x%08lx", err);
LOG("OOPS, error in checking processed buffers : 0x%08lx", err);
break;
}
@@ -93,7 +94,7 @@ static long _ALProcessPlayBuffers(ALVoice *voice, ALuint *bytes_queued) {
ALuint bufid = 0;
alSourceUnqueueBuffers(voice->source, 1, &bufid);
if ((err = alGetError()) != AL_NO_ERROR) {
ERRLOG("OOPS, OpenAL error dequeuing buffer : 0x%08lx", err);
LOG("OOPS, OpenAL error dequeuing buffer : 0x%08lx", err);
break;
}
@@ -103,7 +104,7 @@ static long _ALProcessPlayBuffers(ALVoice *voice, ALuint *bytes_queued) {
};
err = voice->playq->Get(voice->playq, &playNode);
if (err) {
ERRLOG("OOPS, OpenAL bufid %u not found in playlist...", bufid);
LOG("OOPS, OpenAL bufid %u not found in playlist...", bufid);
} else {
_playq_removeNode(voice, &playNode);
}
@@ -112,7 +113,7 @@ static long _ALProcessPlayBuffers(ALVoice *voice, ALuint *bytes_queued) {
ALint play_offset = 0;
alGetSourcei(voice->source, AL_BYTE_OFFSET, &play_offset);
if ((err = alGetError()) != AL_NO_ERROR) {
ERRLOG("OOPS, alGetSourcei AL_BYTE_OFFSET : 0x%08lx", err);
LOG("OOPS, alGetSourcei AL_BYTE_OFFSET : 0x%08lx", err);
break;
}
assert((play_offset >= 0)/* && (play_offset < voice->buffersize)*/);
@@ -219,7 +220,7 @@ static long _ALSubmitBufferToOpenAL(ALVoice *voice) {
alBufferData(playNode.nodeId, voice->format, playNode.bytes, playNode.numBytes, voice->rate);
if ((err = alGetError()) != AL_NO_ERROR) {
_playq_removeNode(voice, &playNode);
ERRLOG("OOPS, Error alBufferData : 0x%08lx", err);
LOG("OOPS, Error alBufferData : 0x%08lx", err);
break;
}
@@ -227,14 +228,14 @@ static long _ALSubmitBufferToOpenAL(ALVoice *voice) {
alSourceQueueBuffers(voice->source, 1, &nodeId);
if ((err = alGetError()) != AL_NO_ERROR) {
_playq_removeNode(voice, &playNode);
ERRLOG("OOPS, Error buffering data : 0x%08lx", err);
LOG("OOPS, Error buffering data : 0x%08lx", err);
break;
}
ALint state = 0;
alGetSourcei(voice->source, AL_SOURCE_STATE, &state);
if ((err = alGetError()) != AL_NO_ERROR) {
ERRLOG("OOPS, Error checking source state : 0x%08lx", err);
LOG("OOPS, Error checking source state : 0x%08lx", err);
break;
}
if ((state != AL_PLAYING) && (state != AL_PAUSED)) {
@@ -313,7 +314,7 @@ static long ALGetStatus(AudioBuffer_s *_this, OUTPARM unsigned long *status) {
ALint state = 0;
alGetSourcei(voice->source, AL_SOURCE_STATE, &state);
if ((err = alGetError()) != AL_NO_ERROR) {
ERRLOG("OOPS, Error checking source state : 0x%08lx", err);
LOG("OOPS, Error checking source state : 0x%08lx", err);
break;
}
@@ -333,7 +334,7 @@ static long ALGetStatus(AudioBuffer_s *_this, OUTPARM unsigned long *status) {
static void _openal_destroyVoice(ALVoice *voice) {
alDeleteSources(1, &voice->source);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Failed to delete source");
LOG("OOPS, Failed to delete source");
}
if (voice->data) {
@@ -343,7 +344,7 @@ static void _openal_destroyVoice(ALVoice *voice) {
for (unsigned int i=0; i<OPENAL_NUM_BUFFERS; i++) {
alDeleteBuffers(1, voice->buffers);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Failed to delete object IDs");
LOG("OOPS, Failed to delete object IDs");
}
}
@@ -359,58 +360,58 @@ static ALVoice *_openal_createVoice(unsigned long numChannels) {
do {
voice = CALLOC(1, sizeof(*voice));
if (voice == NULL) {
ERRLOG("OOPS, Out of memory!");
LOG("OOPS, Out of memory!");
break;
}
alGenBuffers(OPENAL_NUM_BUFFERS, voice->buffers);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Could not create buffers");
LOG("OOPS, Could not create buffers");
break;
}
alGenSources(1, &voice->source);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Could not create source");
LOG("OOPS, Could not create source");
break;
}
// Set parameters so mono sources play out the front-center speaker and won't distance attenuate.
alSource3i(voice->source, AL_POSITION, 0, 0, -1);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Could not set AL_POSITION source parameter");
LOG("OOPS, Could not set AL_POSITION source parameter");
break;
}
alSourcei(voice->source, AL_SOURCE_RELATIVE, AL_TRUE);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Could not set AL_SOURCE_RELATIVE source parameter");
LOG("OOPS, Could not set AL_SOURCE_RELATIVE source parameter");
break;
}
alSourcei(voice->source, AL_ROLLOFF_FACTOR, 0);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Could not set AL_ROLLOFF_FACTOR source parameter");
LOG("OOPS, Could not set AL_ROLLOFF_FACTOR source parameter");
break;
}
#if 0
alSourcei(voice->source, AL_STREAMING, AL_TRUE);
if (alGetError() != AL_NO_ERROR) {
ERRLOG("OOPS, Could not set AL_STREAMING source parameter");
LOG("OOPS, Could not set AL_STREAMING source parameter");
break;
}
#endif
long longBuffers[OPENAL_NUM_BUFFERS];
unsigned int bufs[OPENAL_NUM_BUFFERS];
for (unsigned int i=0; i<OPENAL_NUM_BUFFERS; i++) {
longBuffers[i] = (long)(voice->buffers[i]);
bufs[i] = voice->buffers[i];
}
voice->playq = playq_createPlayQueue(longBuffers, OPENAL_NUM_BUFFERS);
voice->playq = playq_createPlayQueue(bufs, OPENAL_NUM_BUFFERS);
if (!voice->playq) {
ERRLOG("OOPS, Not enough memory for PlayQueue");
LOG("OOPS, Not enough memory for PlayQueue");
break;
}
voice->rate = openal_audio_backend.systemSettings.sampleRateHz;
voice->rate = (ALuint)openal_audio_backend.systemSettings.sampleRateHz;
// Emulator supports only mono and stereo
if (numChannels == 2) {
@@ -422,11 +423,11 @@ static ALVoice *_openal_createVoice(unsigned long numChannels) {
/* Allocate enough space for the temp buffer, given the format */
assert(numChannels == 1 || numChannels == 2);
unsigned long maxSamples = openal_audio_backend.systemSettings.monoBufferSizeSamples * numChannels;
voice->buffersize = maxSamples * openal_audio_backend.systemSettings.bytesPerSample;
voice->buffersize = (ALsizei)maxSamples * (ALsizei)openal_audio_backend.systemSettings.bytesPerSample;
voice->data = CALLOC(1, voice->buffersize);
if (voice->data == NULL) {
ERRLOG("OOPS, Error allocating %d bytes", voice->buffersize);
LOG("OOPS, Error allocating %d bytes", voice->buffersize);
break;
}
@@ -481,16 +482,17 @@ static long openal_createSoundBuffer(const AudioContext_s *audio_context, INOUT
ALCcontext *ctx = (ALCcontext*)(audio_context->_internal);
assert(ctx != NULL);
(void)ctx;
if ((voice = _openal_createVoice(NUM_CHANNELS)) == NULL) {
ERRLOG("OOPS, Cannot create new voice");
LOG("OOPS, Cannot create new voice");
break;
}
ALVoices immutableNode = { /*const*/.source = voice->source };
ALVoices *vnode = CALLOC(1, sizeof(ALVoices));
if (!vnode) {
ERRLOG("OOPS, Not enough memory");
LOG("OOPS, Not enough memory");
break;
}
memcpy(vnode, &immutableNode, sizeof(ALVoices));
@@ -498,7 +500,7 @@ static long openal_createSoundBuffer(const AudioContext_s *audio_context, INOUT
HASH_ADD_INT(voices, source, vnode);
if ((*soundbuf_struct = CALLOC(1, sizeof(AudioBuffer_s))) == NULL) {
ERRLOG("OOPS, Not enough memory");
LOG("OOPS, Not enough memory");
break;
}
@@ -530,6 +532,8 @@ static long openal_systemShutdown(INOUT AudioContext_s **audio_context) {
ALCcontext *ctx = (ALCcontext*) (*audio_context)->_internal;
assert(ctx != NULL);
(void)ctx;
(*audio_context)->_internal = NULL;
FREE(*audio_context);
@@ -539,6 +543,10 @@ static long openal_systemShutdown(INOUT AudioContext_s **audio_context) {
return 0;
}
static const char *openal_systemName(void) {
return "OpenAL";
}
static long openal_systemSetup(INOUT AudioContext_s **audio_context) {
assert(*audio_context == NULL);
assert(voices == NULL);
@@ -556,7 +564,7 @@ static long openal_systemSetup(INOUT AudioContext_s **audio_context) {
if ((ctx = InitAL()) == NULL) {
// NOTE : currently assuming just one OpenAL global context
ERRLOG("OOPS, OpenAL initialize failed");
LOG("OOPS, OpenAL initialize failed");
break;
}
@@ -567,7 +575,7 @@ static long openal_systemSetup(INOUT AudioContext_s **audio_context) {
}
if ((*audio_context = CALLOC(1, sizeof(AudioContext_s))) == NULL) {
ERRLOG("OOPS, Not enough memory");
LOG("OOPS, Not enough memory");
break;
}
@@ -600,7 +608,7 @@ static long openal_systemPause(AudioContext_s *audio_context) {
alSourcePause(vnode->source);
err = alGetError();
if (err != AL_NO_ERROR) {
ERRLOG("OOPS, Failed to pause source : 0x%08lx", err);
LOG("OOPS, Failed to pause source : 0x%08lx", err);
}
}
@@ -616,7 +624,7 @@ static long openal_systemResume(AudioContext_s *audio_context) {
alSourcePlay(vnode->source);
err = alGetError();
if (err != AL_NO_ERROR) {
ERRLOG("OOPS, Failed to pause source : 0x%08lx", err);
LOG("OOPS, Failed to pause source : 0x%08lx", err);
}
}
@@ -625,15 +633,12 @@ static long openal_systemResume(AudioContext_s *audio_context) {
static void _init_openal(void) {
LOG("Initializing OpenAL sound system");
assert((audio_backend == NULL) && "there can only be one!");
openal_audio_backend.name = &openal_systemName;
openal_audio_backend.setup = &openal_systemSetup;
openal_audio_backend.shutdown = &openal_systemShutdown;
openal_audio_backend.pause = &openal_systemPause;
openal_audio_backend.resume = &openal_systemResume;
audio_backend = &openal_audio_backend;
audio_registerBackend(&openal_audio_backend, AUD_PRIO_OPENAL);
}
static __attribute__((constructor)) void __init_openal(void) {

View File

@@ -197,7 +197,7 @@ static long _SLMaybeSubmitAndStart(SLVoice *voice) {
EngineContext_s *ctx = (EngineContext_s *)voice->ctx;
SLresult result = (*(ctx->bqPlayerPlay))->GetPlayState(ctx->bqPlayerPlay, &state);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not get source state : %lu", (unsigned long)result);
LOG("OOPS, could not get source state : %lu", (unsigned long)result);
} else {
if ((state != SL_PLAYSTATE_PLAYING) && (state != SL_PLAYSTATE_PAUSED)) {
LOG("FORCING restart audio buffer queue playback ...");
@@ -338,7 +338,7 @@ static long SLGetStatus(AudioBuffer_s *_this, OUTPARM unsigned long *status) {
SLuint32 state = 0;
result = (*(ctx->bqPlayerPlay))->GetPlayState(ctx->bqPlayerPlay, &state);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not get source state : %lu", (unsigned long)result);
LOG("OOPS, could not get source state : %lu", (unsigned long)result);
break;
}
@@ -428,14 +428,14 @@ static long opensl_createSoundBuffer(const AudioContext_s *audio_context, INOUT
LOG("Creating new SLVoice ...");
voice = CALLOC(1, sizeof(*voice));
if (voice == NULL) {
ERRLOG("OOPS, Out of memory!");
LOG("OOPS, Out of memory!");
break;
}
voice->bufferSize = bufferSize;
// Allocate enough space for the temp buffer (including a maximum allowed overflow)
voice->ringBuffer = CALLOC(1, voice->bufferSize + ctx->submitSize/*max overflow*/);
if (voice->ringBuffer == NULL) {
ERRLOG("OOPS, Error allocating %lu bytes", (unsigned long)voice->bufferSize+ctx->submitSize);
LOG("OOPS, Error allocating %lu bytes", (unsigned long)voice->bufferSize+ctx->submitSize);
break;
}
}
@@ -445,7 +445,7 @@ static long opensl_createSoundBuffer(const AudioContext_s *audio_context, INOUT
voice->ctx = ctx;
if ((*soundbuf_struct = CALLOC(1, sizeof(AudioBuffer_s))) == NULL) {
ERRLOG("OOPS, Not enough memory");
LOG("OOPS, Not enough memory");
break;
}
@@ -526,6 +526,10 @@ static long opensles_systemShutdown(AudioContext_s **audio_context) {
return 0;
}
static const char *opensles_systemName(void) {
return "OpenSLES";
}
static long opensles_systemSetup(INOUT AudioContext_s **audio_context) {
assert(*audio_context == NULL);
@@ -565,28 +569,28 @@ static long opensles_systemSetup(INOUT AudioContext_s **audio_context) {
ctx->submitSize = android_stereoBufferSubmitSizeSamples * opensles_audio_backend.systemSettings.bytesPerSample * NUM_CHANNELS;
ctx->mixBuf = CALLOC(1, ctx->submitSize);
if (ctx->mixBuf == NULL) {
ERRLOG("OOPS, Error allocating %lu bytes", (unsigned long)ctx->submitSize);
LOG("OOPS, Error allocating %lu bytes", (unsigned long)ctx->submitSize);
break;
}
// create basic engine
result = slCreateEngine(&(ctx->engineObject), 0, NULL, /*engineMixIIDCount:*/0, /*engineMixIIDs:*/NULL, /*engineMixReqs:*/NULL);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("Could not create OpenSLES Engine : %lu", (unsigned long)result);
LOG("Could not create OpenSLES Engine : %lu", (unsigned long)result);
break;
}
// realize the engine
result = (*(ctx->engineObject))->Realize(ctx->engineObject, /*asynchronous_realization:*/SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("Could not realize the OpenSLES Engine : %lu", (unsigned long)result);
LOG("Could not realize the OpenSLES Engine : %lu", (unsigned long)result);
break;
}
// get the actual engine interface
result = (*(ctx->engineObject))->GetInterface(ctx->engineObject, SL_IID_ENGINE, &(ctx->engineEngine));
if (result != SL_RESULT_SUCCESS) {
ERRLOG("Could not get the OpenSLES Engine : %lu", (unsigned long)result);
LOG("Could not get the OpenSLES Engine : %lu", (unsigned long)result);
break;
}
@@ -596,21 +600,21 @@ static long opensles_systemSetup(INOUT AudioContext_s **audio_context) {
result = (*(ctx->engineEngine))->CreateOutputMix(ctx->engineEngine, &(ctx->outputMixObject), 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("Could not create output mix : %lu", (unsigned long)result);
LOG("Could not create output mix : %lu", (unsigned long)result);
break;
}
// realize the output mix
result = (*(ctx->outputMixObject))->Realize(ctx->outputMixObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("Could not realize the output mix : %lu", (unsigned long)result);
LOG("Could not realize the output mix : %lu", (unsigned long)result);
break;
}
// create soundcore API wrapper
if ((*audio_context = CALLOC(1, sizeof(AudioContext_s))) == NULL) {
result = -1;
ERRLOG("OOPS, Not enough memory");
LOG("OOPS, Not enough memory");
break;
}
@@ -665,35 +669,35 @@ static long opensles_systemSetup(INOUT AudioContext_s **audio_context) {
result = (*(ctx->engineEngine))->CreateAudioPlayer(ctx->engineEngine, &(ctx->bqPlayerObject), &audioSrc, &audioSnk, _NUM_INTERFACES, ids, req);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not create the BufferQueue player object : %lu", (unsigned long)result);
LOG("OOPS, could not create the BufferQueue player object : %lu", (unsigned long)result);
break;
}
// realize the player
result = (*(ctx->bqPlayerObject))->Realize(ctx->bqPlayerObject, /*asynchronous_realization:*/SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not realize the BufferQueue player object : %lu", (unsigned long)result);
LOG("OOPS, could not realize the BufferQueue player object : %lu", (unsigned long)result);
break;
}
// get the play interface
result = (*(ctx->bqPlayerObject))->GetInterface(ctx->bqPlayerObject, SL_IID_PLAY, &(ctx->bqPlayerPlay));
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not get the play interface : %lu", (unsigned long)result);
LOG("OOPS, could not get the play interface : %lu", (unsigned long)result);
break;
}
// get the buffer queue interface
result = (*(ctx->bqPlayerObject))->GetInterface(ctx->bqPlayerObject, SL_IID_BUFFERQUEUE, &(ctx->bqPlayerBufferQueue));
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not get the BufferQueue play interface : %lu", (unsigned long)result);
LOG("OOPS, could not get the BufferQueue play interface : %lu", (unsigned long)result);
break;
}
// register callback on the buffer queue
result = (*(ctx->bqPlayerBufferQueue))->RegisterCallback(ctx->bqPlayerBufferQueue, bqPlayerCallback, ctx);
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not register BufferQueue callback : %lu", (unsigned long)result);
LOG("OOPS, could not register BufferQueue callback : %lu", (unsigned long)result);
break;
}
@@ -737,12 +741,12 @@ static long opensles_systemResume(AudioContext_s *audio_context) {
do {
if (result != SL_RESULT_SUCCESS) {
ERRLOG("OOPS, could not get source state when attempting to resume : %lu", (unsigned long)result);
LOG("OOPS, could not get source state when attempting to resume : %lu", (unsigned long)result);
break;
}
if (state != SL_PLAYSTATE_PLAYING) {
ERRLOG("WARNING: possible audio lifecycle mismatch ... continuing anyway");
LOG("WARNING: possible audio lifecycle mismatch ... continuing anyway");
}
if (state == SL_PLAYSTATE_PAUSED) {
@@ -760,15 +764,12 @@ static long opensles_systemResume(AudioContext_s *audio_context) {
static void _init_opensl(void) {
LOG("Initializing OpenSLES sound system");
assert(audio_backend == NULL && "there can only be one!");
opensles_audio_backend.name = &opensles_systemName;
opensles_audio_backend.setup = &opensles_systemSetup;
opensles_audio_backend.shutdown = &opensles_systemShutdown;
opensles_audio_backend.pause = &opensles_systemPause;
opensles_audio_backend.resume = &opensles_systemResume;
audio_backend = &opensles_audio_backend;
audio_registerBackend(&opensles_audio_backend, AUD_PRIO_OPENSLES);
}
static __attribute__((constructor)) void __init_opensl(void) {

View File

@@ -24,13 +24,23 @@ static AudioContext_s *audioContext = NULL;
bool audio_isAvailable = false;
float audio_latencySecs = 0.25f;
AudioBackend_s *audio_backend = NULL;
typedef struct backend_node_s {
struct backend_node_s *next;
long order;
AudioBackend_s *backend;
} backend_node_s;
static backend_node_s *head = NULL;
static AudioBackend_s *currentBackend = NULL;
//-----------------------------------------------------------------------------
long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
// CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
if (!audio_isAvailable) {
*audioBuffer = NULL;
@@ -44,7 +54,7 @@ long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
long err = 0;
do {
if (!audioContext) {
ERRLOG("Cannot create sound buffer, no context");
LOG("Cannot create sound buffer, no context");
err = -1;
break;
}
@@ -59,7 +69,7 @@ long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
// CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
if (audioContext) {
audioContext->DestroySoundBuffer(audioContext, audioBuffer);
}
@@ -67,22 +77,17 @@ void audio_destroySoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
bool audio_init(void) {
// CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
if (audio_isAvailable) {
return true;
}
do {
if (!audio_backend) {
LOG("No backend audio available, cannot initialize soundcore");
break;
}
if (audioContext) {
audio_backend->shutdown(&audioContext);
currentBackend->shutdown(&audioContext);
}
long err = audio_backend->setup((AudioContext_s**)&audioContext);
long err = currentBackend->setup((AudioContext_s**)&audioContext);
if (err) {
LOG("Failed to create an audio context!");
break;
@@ -96,35 +101,35 @@ bool audio_init(void) {
void audio_shutdown(void) {
// CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
if (!audio_isAvailable) {
return;
}
audio_backend->shutdown(&audioContext);
currentBackend->shutdown(&audioContext);
audio_isAvailable = false;
}
void audio_pause(void) {
// CPU thread owns audio lifecycle (see note above)
// Deadlock on Kindle Fire 1st Gen if audio_pause() and audio_resume() happen off CPU thread ...
#ifdef __APPLE__
#if TARGET_OS_MAC || TARGET_OS_PHONE
# warning FIXME TODO : this assert is firing on iOS port ... but the assert is valid ... fix soon
#else
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
#endif
if (!audio_isAvailable) {
return;
}
audio_backend->pause(audioContext);
currentBackend->pause(audioContext);
}
void audio_resume(void) {
// CPU thread owns audio lifecycle (see note above)
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
if (!audio_isAvailable) {
return;
}
audio_backend->resume(audioContext);
currentBackend->resume(audioContext);
}
void audio_setLatency(float latencySecs) {
@@ -135,3 +140,100 @@ float audio_getLatency(void) {
return audio_latencySecs;
}
//-----------------------------------------------------------------------------
void audio_registerBackend(AudioBackend_s *backend, long order) {
backend_node_s *node = MALLOC(sizeof(backend_node_s));
assert((uintptr_t)node);
node->next = NULL;
node->order = order;
node->backend = backend;
backend_node_s *p0 = NULL;
backend_node_s *p = head;
while (p && (order > p->order)) {
p0 = p;
p = p->next;
}
if (p0) {
p0->next = node;
} else {
head = node;
}
node->next = p;
currentBackend = head->backend;
}
void audio_printBackends(FILE *out) {
backend_node_s *p = head;
int count = 0;
while (p) {
const char *name = p->backend->name();
if (count++) {
fprintf(out, "|");
}
fprintf(out, "%s", name);
p = p->next;
}
}
static const char *_null_backend_name(void);
void audio_chooseBackend(const char *name) {
if (!name) {
name = _null_backend_name();
}
backend_node_s *p = head;
while (p) {
const char *bname = p->backend->name();
if (strcasecmp(name, bname) == 0) {
currentBackend = p->backend;
LOG("Setting current audio backend to %s", name);
break;
}
p = p->next;
}
}
AudioBackend_s *audio_getCurrentBackend(void) {
return currentBackend;
}
static const char *_null_backend_name(void) {
return "none";
}
static long _null_backend_setup(INOUT AudioContext_s **audio_context) {
*audio_context = NULL;
return -1;
}
static long _null_backend_shutdown(INOUT AudioContext_s **audio_context) {
*audio_context = NULL;
return -1;
}
static long _null_backend_pause(AudioContext_s *audio_context) {
return -1;
}
static long _null_backend_resume(AudioContext_s *audio_context) {
return -1;
}
static void _init_soundcore(void) {
LOG("Initializing audio subsystem");
static AudioBackend_s null_backend = { { 0 } };
null_backend.name = &_null_backend_name;
null_backend.setup = &_null_backend_setup;
null_backend.shutdown = &_null_backend_shutdown;
null_backend.pause = &_null_backend_pause;
null_backend.resume = &_null_backend_resume;
audio_registerBackend(&null_backend, AUD_PRIO_NULL);
}
static __attribute__((constructor)) void __init_soundcore(void) {
emulator_registerStartupCallback(CTOR_PRIORITY_LATE, &_init_soundcore);
}

View File

@@ -137,6 +137,8 @@ typedef struct AudioBackend_s {
AudioSettings_s systemSettings;
const char *(*name)(void);
// basic backend functionality controlled by soundcore
PRIVATE long (*setup)(INOUT AudioContext_s **audio_context);
PRIVATE long (*shutdown)(INOUT AudioContext_s **audio_context);
@@ -146,7 +148,19 @@ typedef struct AudioBackend_s {
} AudioBackend_s;
// Audio backend registered at CTOR time
extern AudioBackend_s *audio_backend;
enum {
AUD_PRIO_ALSA = 10,
AUD_PRIO_OPENAL = 20,
AUD_PRIO_OPENSLES = 30,
AUD_PRIO_NULL = 100,
};
void audio_registerBackend(AudioBackend_s *backend, long prio);
void audio_printBackends(FILE *out);
void audio_chooseBackend(const char *name);
AudioBackend_s *audio_getCurrentBackend(void);
#endif /* whole file */

View File

@@ -31,6 +31,9 @@
#define SPKR_SILENT_STEP 1
// TODO FIXME : still need to investigate better way to fix audio glitches when fast-loading (auto-adjusting speed) ...
#define HACKISHLY_REDUCE_AUDIO_GLITCHES_FOR_FAST_LOADING 1
static unsigned long bufferTotalSize = 0;
static unsigned long bufferSizeIdealMin = 0;
static unsigned long bufferSizeIdealMax = 0;
@@ -40,7 +43,7 @@ static bool speaker_isAvailable = false;
static int16_t *samples_buffer = NULL; // holds max 1 second of samples
static int16_t *remainder_buffer = NULL; // holds enough to create one sample (averaged)
static unsigned int samples_buffer_idx = 0;
static unsigned long samples_buffer_idx = 0;
static unsigned int remainder_buffer_size = 0;
static unsigned long remainder_buffer_size_max = 0;
static unsigned int remainder_buffer_idx = 0;
@@ -102,7 +105,7 @@ static void _speaker_init_timing(void) {
// 46.28 //e cycles for 22.05kHz sample rate
// AppleWin NOTE : use integer value: Better for MJ Mahon's RT.SYNTH.DSK (integer multiples of 1.023MHz Clk)
cycles_per_sample = (unsigned int)(cycles_persec_target / (double)audio_backend->systemSettings.sampleRateHz);
cycles_per_sample = (unsigned int)(cycles_persec_target / (double)audio_getCurrentBackend()->systemSettings.sampleRateHz);
unsigned int last_remainder_buffer_size = remainder_buffer_size;
remainder_buffer_size = (unsigned int)cycles_per_sample;
@@ -122,7 +125,7 @@ static void _speaker_init_timing(void) {
cycles_last_update = 0;
}
LOG("Speaker initialize timing ... cycles_persec_target:%f cycles_per_sample:%f speaker sampleRateHz:%lu", cycles_persec_target, cycles_per_sample, audio_backend->systemSettings.sampleRateHz);
LOG("Speaker initialize timing ... cycles_persec_target:%f cycles_per_sample:%f speaker sampleRateHz:%lu", cycles_persec_target, cycles_per_sample, audio_getCurrentBackend()->systemSettings.sampleRateHz);
if (is_fullspeed) {
remainder_buffer_idx = 0;
@@ -203,9 +206,13 @@ static void _speaker_update(/*bool toggled*/) {
if (NUM_CHANNELS == 2) {
samples_buffer[samples_buffer_idx++] = speaker_data;
}
#if !defined(ANDROID)
#if HACKISHLY_REDUCE_AUDIO_GLITCHES_FOR_FAST_LOADING
if (speaker_going_silent && speaker_data) {
speaker_data -= SPKR_SILENT_STEP;
if (speaker_data < 0) {
speaker_data += SPKR_SILENT_STEP;
} else {
speaker_data -= SPKR_SILENT_STEP;
}
}
#endif
--num_samples;
@@ -257,7 +264,7 @@ static void _submit_samples_buffer_fullspeed(void) {
return;
}
unsigned int num_samples_pad = (bufferSizeIdealMax - bytes_queued) / sizeof(int16_t);
unsigned long num_samples_pad = (bufferSizeIdealMax - bytes_queued) / sizeof(int16_t);
if (num_samples_pad == 0) {
return;
}
@@ -282,7 +289,7 @@ static void _submit_samples_buffer_fullspeed(void) {
// Submits samples from the samples_buffer to the audio system backend when running at a normal scaled-speed. This also
// generates cycles feedback to the main CPU timing routine depending on the needs of the streaming audio (more or less
// data).
static unsigned int _submit_samples_buffer(const unsigned long num_channel_samples) {
static unsigned long _submit_samples_buffer(const unsigned long num_channel_samples) {
assert(num_channel_samples);
@@ -319,7 +326,7 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl
// copy samples to audio system backend
//
const unsigned int bytes_free = bufferTotalSize - bytes_queued;
const unsigned long bytes_free = bufferTotalSize - bytes_queued;
unsigned long requested_samples = num_channel_samples;
unsigned long requested_buffer_size = num_channel_samples * sizeof(int16_t);
@@ -338,12 +345,12 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl
unsigned long counter = 0;
do {
if (speakerBuffer->Lock(speakerBuffer, curr_buffer_size, &system_samples_buffer, &system_buffer_size)) {
ERRLOG("Problem locking speaker buffer");
LOG("Problem locking speaker buffer");
break;
}
if (system_buffer_size > maxSpeakerBytes) {
RELEASE_LOG("AVOIDING BUFOVER...");
LOG("AVOIDING BUFOVER...");
system_buffer_size = maxSpeakerBytes;
requested_buffer_size = maxSpeakerBytes;
}
@@ -352,7 +359,7 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl
err = speakerBuffer->Unlock(speakerBuffer, system_buffer_size);
if (err) {
ERRLOG("Problem unlocking speaker buffer");
LOG("Problem unlocking speaker buffer");
break;
}
@@ -369,7 +376,7 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl
// speaker public API functions
void speaker_destroy(void) {
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
speaker_isAvailable = false;
audio_destroySoundBuffer(&speakerBuffer);
FREE(samples_buffer);
@@ -377,7 +384,7 @@ void speaker_destroy(void) {
}
void speaker_init(void) {
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
long err = 0;
speaker_isAvailable = false;
@@ -387,20 +394,20 @@ void speaker_init(void) {
break;
}
assert(audio_backend->systemSettings.bytesPerSample == sizeof(int16_t));
assert(audio_getCurrentBackend()->systemSettings.bytesPerSample == sizeof(int16_t));
assert(NUM_CHANNELS == 2 || NUM_CHANNELS == 1);
if (NUM_CHANNELS == 2) {
bufferTotalSize = audio_backend->systemSettings.stereoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample * NUM_CHANNELS;
bufferTotalSize = audio_getCurrentBackend()->systemSettings.stereoBufferSizeSamples * audio_getCurrentBackend()->systemSettings.bytesPerSample * NUM_CHANNELS;
} else {
bufferTotalSize = audio_backend->systemSettings.monoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample;
bufferTotalSize = audio_getCurrentBackend()->systemSettings.monoBufferSizeSamples * audio_getCurrentBackend()->systemSettings.bytesPerSample;
}
bufferSizeIdealMin = bufferTotalSize/4;
bufferSizeIdealMax = bufferTotalSize/2;
channelsSampleRateHz = audio_backend->systemSettings.sampleRateHz * NUM_CHANNELS;
LOG("Speaker initializing with %lu buffer size (bytes), sample rate of %lu", bufferTotalSize, audio_backend->systemSettings.sampleRateHz);
channelsSampleRateHz = audio_getCurrentBackend()->systemSettings.sampleRateHz * NUM_CHANNELS;
LOG("Speaker initializing with %lu buffer size (bytes), sample rate of %lu", bufferTotalSize, audio_getCurrentBackend()->systemSettings.sampleRateHz);
remainder_buffer_size_max = ((CLK_6502_INT*(unsigned long)CPU_SCALE_FASTEST)/audio_backend->systemSettings.sampleRateHz)+1;
remainder_buffer_size_max = ((CLK_6502_INT*(unsigned long)CPU_SCALE_FASTEST)/audio_getCurrentBackend()->systemSettings.sampleRateHz)+1;
samples_buffer = CALLOC(1, channelsSampleRateHz * sizeof(int16_t));
if (!samples_buffer) {
@@ -443,7 +450,9 @@ void speaker_flush(void) {
return;
}
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
timing_checkpointCycles();
if (is_fullspeed) {
cycles_quiet_time = cycles_count_total;
@@ -463,7 +472,7 @@ void speaker_flush(void) {
// After 0.2sec of //e cycles time set inactive flag (allows auto-switch to full speed for fast disk access)
speaker_recently_active = false;
} else if ((speaker_data != 0) && (cycles_count_total - cycles_quiet_time > cycles_diff)) {
#if defined(ANDROID)
#if !HACKISHLY_REDUCE_AUDIO_GLITCHES_FOR_FAST_LOADING
// OpenSLES seems to be able to pause output without the nasty pops that I hear with OpenAL on Linux
// desktop. So this speaker_going_silent hack is not needed. There is also a noticeable glitch in
// OpenSLES when this codepath is enabled.
@@ -481,7 +490,7 @@ void speaker_flush(void) {
}
_speaker_update(/*toggled:false*/);
unsigned int samples_used = 0;
unsigned long samples_used = 0;
if (is_fullspeed) {
assert(!samples_buffer_idx && "should be all quiet samples");
_submit_samples_buffer_fullspeed();
@@ -512,9 +521,9 @@ double speaker_cyclesPerSample(void) {
GLUE_C_READ(speaker_toggle)
{
assert(pthread_self() == cpu_thread_id);
ASSERT_ON_CPU_THREAD();
timing_checkpoint_cycles();
timing_checkpointCycles();
#if SPEAKER_TRACING
// output cycle count delta when toggled
@@ -533,11 +542,9 @@ GLUE_C_READ(speaker_toggle)
speaker_accessed_since_last_flush = true;
speaker_recently_active = true;
#if !defined(MOBILE_DEVICE)
if (timing_shouldAutoAdjustSpeed()) {
is_fullspeed = false;
}
#endif
if (speaker_isAvailable) {
_speaker_update(/*toggled:true*/);
@@ -545,11 +552,7 @@ GLUE_C_READ(speaker_toggle)
if (!is_fullspeed) {
if (speaker_data == speaker_amplitude) {
#ifdef ANDROID
speaker_data = -speaker_amplitude;
#else
speaker_data = 0;
#endif
} else {
speaker_data = speaker_amplitude;
}

View File

@@ -16,10 +16,10 @@
// between speaker and mockingboard
#define SPKR_DATA_INIT (SHRT_MAX>>3) // 0x0FFF
void speaker_init(void);
void speaker_destroy(void);
void speaker_init(void) CALL_ON_CPU_THREAD;
void speaker_destroy(void) CALL_ON_CPU_THREAD;
void speaker_reset(void);
void speaker_flush(void);
void speaker_flush(void) CALL_ON_CPU_THREAD;
bool speaker_isActive(void);
/*

View File

@@ -16,21 +16,6 @@
# define _GNU_SOURCE 1
#endif
#ifdef __APPLE__
# warning DEFINING CUSTOM TEMP_FAILURE_RETRY(x) macro
# define TEMP_FAILURE_RETRY(exp) ({ \
typeof (exp) _rc; \
do { \
_rc = (exp); \
if (_rc == -1 && (errno == EINTR || errno == EAGAIN) ) { \
usleep(10); \
} else { \
break; \
} \
} while (1); \
_rc; })
#endif
// custom annotations
#define INOUT
#define INPARM
@@ -41,6 +26,18 @@
#define PUBLIC
#define READONLY
#define CALL_ON_UI_THREAD
#define ASSERT_ON_UI_THREAD() \
assert(video_isRenderThread())
#define ASSERT_NOT_ON_UI_THREAD() \
assert(!video_isRenderThread())
#define CALL_ON_CPU_THREAD
#define ASSERT_ON_CPU_THREAD() \
assert(timing_isCPUThread())
#define ASSERT_NOT_ON_CPU_THREAD() \
assert(!timing_isCPUThread())
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -72,38 +69,30 @@
#include "vm.h"
#include "timing.h"
#include "cpu.h"
#include "display.h"
#include "disk.h"
#include "interface.h"
#include "display.h"
#include "video/video.h"
#include "disk.h"
#include "keys.h"
#include "joystick.h"
#include "glue.h"
#include "prefs.h"
#include "zlib-helpers.h"
#include "meta/trace.h"
#include "meta/systrace.h"
#ifdef __APPLE__
#include "darwin-shim.h"
#import <CoreFoundation/CoreFoundation.h>
#if __APPLE__
# include "meta/darwin-shim.h"
# if TARGET_OS_MAC || TARGET_OS_PHONE
# import <CoreFoundation/CoreFoundation.h>
# endif
#endif
#if VIDEO_OPENGL
#include "video_util/glUtil.h"
// 2015/04/01 ... early calls to glGetError()--before a context exists--causes segfaults on MacOS X
extern bool safe_to_do_opengl_logging;
static inline GLenum safeGLGetError(void) {
if (safe_to_do_opengl_logging && video_isRenderThread()) {
return glGetError();
}
return (GLenum)0;
}
#else
#define GLenum int
#define safeGLGetError() 0
#define glGetError() 0
# include "video_util/glUtil.h"
#endif
#include "meta/log.h"
#include "meta/debug.h"
#include "audio/soundcore.h"
@@ -157,165 +146,26 @@ static inline GLenum safeGLGetError(void) {
_rc; })
extern bool do_logging;
#ifdef ANDROID
static const char *log_end = "";
# include <android/log.h>
# define QUIT_FUNCTION(x) exit(x)
# define _LOG_CMD(str) __android_log_print(ANDROID_LOG_ERROR, "apple2ix", "%s", str)
#else
extern FILE *error_log;
static const char *log_end = "\n";
# define QUIT_FUNCTION(x) exit(x)
# define _LOG_CMD(str) \
do { \
if (UNLIKELY(!error_log)) { \
error_log = stderr; \
} \
fprintf(error_log, "%s", str); \
} while (0);
#endif
#define _MYFILE_ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define _LOG(...) \
do { \
int _err = errno; \
errno = 0; \
\
char *syserr_str = NULL; \
char *glerr_str = NULL; \
if (_err) { \
asprintf(&syserr_str, " (syserr:%s)", strerror(_err)); \
} \
if (_glerr) { \
asprintf(&glerr_str, " (glerr:%04X)", _glerr); \
} \
\
char *buf0 = NULL; \
asprintf(&buf0, __VA_ARGS__); \
\
char *buf = NULL; \
asprintf(&buf, "%s:%d (%s) -%s%s %s%s", _MYFILE_, __LINE__, __func__, syserr_str ? : "", glerr_str ? : "", buf0, log_end); \
\
_LOG_CMD(buf); \
\
free(buf0); \
free(buf); \
if (syserr_str) { \
free(syserr_str); \
} \
if (glerr_str) { \
free(glerr_str); \
} \
} while (0)
#if !defined(NDEBUG) || (defined(NDEBUG) && defined(ANDROID))
#ifdef ANDROID
// Apparently some non-conformant Android devices (ahem, Spamsung, ahem) do not actually let me see what the assert
// actually was before aborting/segfaulting ...
# undef assert
# define assert(e) \
do { \
if ((e)) { \
/* ... */ \
} else { \
LOG( "!!! ASSERT !!! : " #e ); \
sleep(1); \
__assert2(_MYFILE_, __LINE__, __func__, #e); \
} \
} while (0)
#endif
#define LOG(...) \
if (do_logging) { \
errno = 0; \
GLenum _glerr = 0; \
_LOG(__VA_ARGS__); \
} //
#define ERRLOG(...) \
if (do_logging) { \
GLenum _glerr = safeGLGetError(); \
_LOG(__VA_ARGS__); \
while ( (_glerr = safeGLGetError()) ) { \
_LOG(__VA_ARGS__); \
} \
} //
#define GL_ERRLOG(...) \
if (do_logging) { \
GLenum _glerr = 0; \
while ( (_glerr = safeGLGetError()) ) { \
_LOG(__VA_ARGS__); \
} \
} //
#define ERRQUIT(...) \
do { \
GLenum _glerr = safeGLGetError(); \
_LOG(__VA_ARGS__); \
while ( (_glerr = safeGLGetError()) ) { \
_LOG(__VA_ARGS__); \
} \
QUIT_FUNCTION(1); \
} while (0)
#define GL_ERRQUIT(...) \
do { \
GLenum _glerr = 0; \
while ( (_glerr = safeGLGetError()) ) { \
_LOG(__VA_ARGS__); \
QUIT_FUNCTION(_glerr); \
} \
} while (0)
#else // NDEBUG
#define ERRLOG(...) \
do { } while (0)
#define ERRQUIT(...) \
do { } while (0)
#define LOG(...) \
do { } while (0)
#define GL_ERRLOG(...) \
do { } while (0)
#define GL_ERRQUIT(...) \
do { } while (0)
#endif // NDEBUG
#define RELEASE_ERRLOG(...) \
do { \
GLenum _glerr = 0; \
_LOG(__VA_ARGS__); \
} while (0)
#define RELEASE_LOG(...) \
do { \
GLenum _glerr = safeGLGetError(); \
errno = 0; \
_LOG(__VA_ARGS__); \
} while (0)
#define RELEASE_BREAK() \
do { \
/* BOOM */ \
char *ptr = (char *)0xABADF000; \
*ptr++ = '\0';\
} while (1);
// memory management
#include "memmngt.h"
#include "meta/memmngt.h"
// branch prediction
#define LIKELY(x) __builtin_expect((x), true)
#define UNLIKELY(x) __builtin_expect((x), false)
#if !defined(TEMP_FAILURE_RETRY)
# define TEMP_FAILURE_RETRY(exp) ({ \
typeof (exp) _rc; \
do { \
_rc = (exp); \
if (_rc == -1 && (errno == EINTR || errno == EAGAIN) ) { \
usleep(10); \
} else { \
break; \
} \
} while (1); \
_rc; })
#endif
#endif // whole file

View File

@@ -22,20 +22,7 @@
#include "common.h"
uint16_t cpu65_pc;
uint8_t cpu65_a;
uint8_t cpu65_f;
uint8_t cpu65_x;
uint8_t cpu65_y;
uint8_t cpu65_sp;
uint16_t cpu65_ea;
uint8_t cpu65_d;
uint8_t cpu65_rw;
uint8_t cpu65_opcode;
uint8_t cpu65_opcycles;
uint8_t cpu65__signal = 0;
cpu65_run_args_s run_args = { 0 };
static pthread_mutex_t irq_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -55,9 +42,9 @@ static FILE *cpu_trace_fp = NULL;
// ----------------------------------------------------------------------------
// 65c02 Opcode Jump Table
extern void op_BRK(), op_ORA_ind_x(), op_UNK_65c02(), op_TSB_zpage(), op_ORA_zpage(), op_ASL_zpage(), op_RMB0_65c02(), op_PHP(), op_ORA_imm(), op_ASL_acc(), op_TSB_abs(), op_ORA_abs(), op_ASL_abs(), op_BBR0_65c02(), op_BPL(), op_ORA_ind_y(), op_ORA_ind_zpage(), op_TRB_zpage(), op_ORA_zpage_x(), op_ASL_zpage_x(), op_RMB1_65c02(), op_CLC(), op_ORA_abs_y(), op_INA(), op_TRB_abs(), op_ORA_abs_x(), op_ASL_abs_x(), op_BBR1_65c02(), op_JSR(), op_AND_ind_x(), op_BIT_zpage(), op_AND_zpage(), op_ROL_zpage(), op_RMB2_65c02(), op_PLP(), op_AND_imm(), op_ROL_acc(), op_BIT_abs(), op_AND_abs(), op_ROL_abs(), op_BBR2_65c02(), op_BMI(), op_AND_ind_y(), op_AND_ind_zpage(), op_BIT_zpage_x(), op_AND_zpage_x(), op_ROL_zpage_x(), op_RMB3_65c02(), op_SEC(), op_AND_abs_y(), op_DEA(), op_BIT_abs_x(), op_AND_abs_x(), op_ROL_abs_x(), op_BBR3_65c02(), op_RTI(), op_EOR_ind_x(), op_EOR_zpage(), op_LSR_zpage(), op_RMB4_65c02(), op_PHA(), op_EOR_imm(), op_LSR_acc(), op_JMP_abs(), op_EOR_abs(), op_LSR_abs(), op_BBR4_65c02(), op_BVC(), op_EOR_ind_y(), op_EOR_ind_zpage(), op_EOR_zpage_x(), op_LSR_zpage_x(), op_RMB5_65c02(), op_CLI(), op_EOR_abs_y(), op_PHY(), op_EOR_abs_x(), op_LSR_abs_x(), op_BBR5_65c02(), op_RTS(), op_ADC_ind_x(), op_STZ_zpage(), op_ADC_zpage(), op_ROR_zpage(), op_RMB6_65c02(), op_PLA(), op_ADC_imm(), op_ROR_acc(), op_JMP_ind(), op_ADC_abs(), op_ROR_abs(), op_BBR6_65c02(), op_BVS(), op_ADC_ind_y(), op_ADC_ind_zpage(), op_STZ_zpage_x(), op_ADC_zpage_x(), op_ROR_zpage_x(), op_RMB7_65c02(), op_SEI(), op_ADC_abs_y(), op_PLY(), op_JMP_abs_ind_x(), op_ADC_abs_x(), op_ROR_abs_x(), op_BBR7_65c02(), op_BRA(), op_STA_ind_x(), op_STY_zpage(), op_STA_zpage(), op_STX_zpage(), op_SMB0_65c02(), op_DEY(), op_BIT_imm(), op_TXA(), op_STY_abs(), op_STA_abs(), op_STX_abs(), op_BBS0_65c02(), op_BCC(), op_STA_ind_y(), op_STA_ind_zpage(), op_STY_zpage_x(), op_STA_zpage_x(), op_STX_zpage_y(), op_SMB1_65c02(), op_TYA(), op_STA_abs_y(), op_TXS(), op_STZ_abs(), op_STA_abs_x(), op_STZ_abs_x(), op_BBS1_65c02(), op_LDY_imm(), op_LDA_ind_x(), op_LDX_imm(), op_LDY_zpage(), op_LDA_zpage(), op_LDX_zpage(), op_SMB2_65c02(), op_TAY(), op_LDA_imm(), op_TAX(), op_LDY_abs(), op_LDA_abs(), op_LDX_abs(), op_BBS2_65c02(), op_BCS(), op_LDA_ind_y(), op_LDA_ind_zpage(), op_LDY_zpage_x(), op_LDA_zpage_x(), op_LDX_zpage_y(), op_SMB3_65c02(), op_CLV(), op_LDA_abs_y(), op_TSX(), op_LDY_abs_x(), op_LDA_abs_x(), op_LDX_abs_y(), op_BBS3_65c02(), op_CPY_imm(), op_CMP_ind_x(), op_CPY_zpage(), op_CMP_zpage(), op_DEC_zpage(), op_SMB4_65c02(), op_INY(), op_CMP_imm(), op_DEX(), op_WAI_65c02(), op_CPY_abs(), op_CMP_abs(), op_DEC_abs(), op_BBS4_65c02(), op_BNE(), op_CMP_ind_y(), op_CMP_ind_zpage(), op_CMP_zpage_x(), op_DEC_zpage_x(), op_SMB5_65c02(), op_CLD(), op_CMP_abs_y(), op_PHX(), op_STP_65c02(), op_CMP_abs_x(), op_DEC_abs_x(), op_BBS5_65c02(), op_CPX_imm(), op_SBC_ind_x(), op_CPX_zpage(), op_SBC_zpage(), op_INC_zpage(), op_SMB6_65c02(), op_INX(), op_SBC_imm(), op_NOP(), op_CPX_abs(), op_SBC_abs(), op_INC_abs(), op_BBS6_65c02(), op_BEQ(), op_SBC_ind_y(), op_SBC_ind_zpage(), op_SBC_zpage_x(), op_INC_zpage_x(), op_SMB7_65c02(), op_SED(), op_SBC_abs_y(), op_PLX(), op_SBC_abs_x(), op_INC_abs_x(), op_BBS7_65c02();
extern void op_BRK(void), op_ORA_ind_x(void), op_UNK_65c02(void), op_TSB_zpage(void), op_ORA_zpage(void), op_ASL_zpage(void), op_RMB0_65c02(void), op_PHP(void), op_ORA_imm(void), op_ASL_acc(void), op_TSB_abs(void), op_ORA_abs(void), op_ASL_abs(void), op_BBR0_65c02(void), op_BPL(void), op_ORA_ind_y(void), op_ORA_ind_zpage(void), op_TRB_zpage(void), op_ORA_zpage_x(void), op_ASL_zpage_x(void), op_RMB1_65c02(void), op_CLC(void), op_ORA_abs_y(void), op_INA(void), op_TRB_abs(void), op_ORA_abs_x(void), op_ASL_abs_x(void), op_BBR1_65c02(void), op_JSR(void), op_AND_ind_x(void), op_BIT_zpage(void), op_AND_zpage(void), op_ROL_zpage(void), op_RMB2_65c02(void), op_PLP(void), op_AND_imm(void), op_ROL_acc(void), op_BIT_abs(void), op_AND_abs(void), op_ROL_abs(void), op_BBR2_65c02(void), op_BMI(void), op_AND_ind_y(void), op_AND_ind_zpage(void), op_BIT_zpage_x(void), op_AND_zpage_x(void), op_ROL_zpage_x(void), op_RMB3_65c02(void), op_SEC(void), op_AND_abs_y(void), op_DEA(void), op_BIT_abs_x(void), op_AND_abs_x(void), op_ROL_abs_x(void), op_BBR3_65c02(void), op_RTI(void), op_EOR_ind_x(void), op_EOR_zpage(void), op_LSR_zpage(void), op_RMB4_65c02(void), op_PHA(void), op_EOR_imm(void), op_LSR_acc(void), op_JMP_abs(void), op_EOR_abs(void), op_LSR_abs(void), op_BBR4_65c02(void), op_BVC(void), op_EOR_ind_y(void), op_EOR_ind_zpage(void), op_EOR_zpage_x(void), op_LSR_zpage_x(void), op_RMB5_65c02(void), op_CLI(void), op_EOR_abs_y(void), op_PHY(void), op_EOR_abs_x(void), op_LSR_abs_x(void), op_BBR5_65c02(void), op_RTS(void), op_ADC_ind_x(void), op_STZ_zpage(void), op_ADC_zpage(void), op_ROR_zpage(void), op_RMB6_65c02(void), op_PLA(void), op_ADC_imm(void), op_ROR_acc(void), op_JMP_ind(void), op_ADC_abs(void), op_ROR_abs(void), op_BBR6_65c02(void), op_BVS(void), op_ADC_ind_y(void), op_ADC_ind_zpage(void), op_STZ_zpage_x(void), op_ADC_zpage_x(void), op_ROR_zpage_x(void), op_RMB7_65c02(void), op_SEI(void), op_ADC_abs_y(void), op_PLY(void), op_JMP_abs_ind_x(void), op_ADC_abs_x(void), op_ROR_abs_x(void), op_BBR7_65c02(void), op_BRA(void), op_STA_ind_x(void), op_STY_zpage(void), op_STA_zpage(void), op_STX_zpage(void), op_SMB0_65c02(void), op_DEY(void), op_BIT_imm(void), op_TXA(void), op_STY_abs(void), op_STA_abs(void), op_STX_abs(void), op_BBS0_65c02(void), op_BCC(void), op_STA_ind_y(void), op_STA_ind_zpage(void), op_STY_zpage_x(void), op_STA_zpage_x(void), op_STX_zpage_y(void), op_SMB1_65c02(void), op_TYA(void), op_STA_abs_y(void), op_TXS(void), op_STZ_abs(void), op_STA_abs_x(void), op_STZ_abs_x(void), op_BBS1_65c02(void), op_LDY_imm(void), op_LDA_ind_x(void), op_LDX_imm(void), op_LDY_zpage(void), op_LDA_zpage(void), op_LDX_zpage(void), op_SMB2_65c02(void), op_TAY(void), op_LDA_imm(void), op_TAX(void), op_LDY_abs(void), op_LDA_abs(void), op_LDX_abs(void), op_BBS2_65c02(void), op_BCS(void), op_LDA_ind_y(void), op_LDA_ind_zpage(void), op_LDY_zpage_x(void), op_LDA_zpage_x(void), op_LDX_zpage_y(void), op_SMB3_65c02(void), op_CLV(void), op_LDA_abs_y(void), op_TSX(void), op_LDY_abs_x(void), op_LDA_abs_x(void), op_LDX_abs_y(void), op_BBS3_65c02(void), op_CPY_imm(void), op_CMP_ind_x(void), op_CPY_zpage(void), op_CMP_zpage(void), op_DEC_zpage(void), op_SMB4_65c02(void), op_INY(void), op_CMP_imm(void), op_DEX(void), op_WAI_65c02(void), op_CPY_abs(void), op_CMP_abs(void), op_DEC_abs(void), op_BBS4_65c02(void), op_BNE(void), op_CMP_ind_y(void), op_CMP_ind_zpage(void), op_CMP_zpage_x(void), op_DEC_zpage_x(void), op_SMB5_65c02(void), op_CLD(void), op_CMP_abs_y(void), op_PHX(void), op_STP_65c02(void), op_CMP_abs_x(void), op_DEC_abs_x(void), op_BBS5_65c02(void), op_CPX_imm(void), op_SBC_ind_x(void), op_CPX_zpage(void), op_SBC_zpage(void), op_INC_zpage(void), op_SMB6_65c02(void), op_INX(void), op_SBC_imm(void), op_NOP(void), op_CPX_abs(void), op_SBC_abs(void), op_INC_abs(void), op_BBS6_65c02(void), op_BEQ(void), op_SBC_ind_y(void), op_SBC_ind_zpage(void), op_SBC_zpage_x(void), op_INC_zpage_x(void), op_SMB7_65c02(void), op_SED(void), op_SBC_abs_y(void), op_PLX(void), op_SBC_abs_x(void), op_INC_abs_x(void), op_BBS7_65c02(void);
void *const cpu65__opcodes[256] = {
void *cpu65__opcodes[256] = {
op_BRK, // 00
op_ORA_ind_x,
op_UNK_65c02,
@@ -620,35 +607,62 @@ static void init_flags_conversion_tables(void) {
}
}
void cpu65_init(void)
{
init_flags_conversion_tables();
cpu65__signal = 0;
cpu65_pc = 0x0;
cpu65_ea = 0x0;
cpu65_a = 0xFF;
cpu65_x = 0xFF;
cpu65_y = 0xFF;
cpu65_f = (C_Flag_6502|X_Flag_6502|I_Flag_6502|V_Flag_6502|B_Flag_6502|Z_Flag_6502|N_Flag_6502);
cpu65_sp = 0xFC;
static __attribute__((constructor)) void __init_cpu65(void) {
// emulator_registerStartupCallback(CTOR_PRIORITY_LATE, &_init_cpu65); -- 2018/01/15 NOTE : too late for testcpu.c
run_args.cpu65_vmem_r = &cpu65_vmem_r[0];
run_args.cpu65_vmem_w = &cpu65_vmem_w[0];
run_args.cpu65_flags_encode = &cpu65_flags_encode[0];
run_args.cpu65_flags_decode = &cpu65_flags_decode[0];
run_args.cpu65__opcodes = &cpu65__opcodes[0];
run_args.cpu65__opcycles = &cpu65__opcycles[0];
run_args.interrupt_vector = 0xFFFE;
run_args.reset_vector = 0xFFFC;
#if CPU_TRACING
extern void cpu65_trace_prologue(uint16_t, uint8_t);
run_args.cpu65_trace_prologue = cpu65_trace_prologue;
extern void cpu65_trace_arg(uint16_t, uint8_t);
run_args.cpu65_trace_arg = cpu65_trace_arg;
extern void cpu65_trace_epilogue(uint16_t, uint8_t);
run_args.cpu65_trace_epilogue = cpu65_trace_epilogue;
extern void cpu65_trace_irq(uint16_t, uint8_t);
run_args.cpu65_trace_irq = cpu65_trace_irq;
#endif
#ifndef NDEBUG
extern uint8_t (*debug_illegal_bcd)(uint16_t);
run_args.debug_illegal_bcd = debug_illegal_bcd;
#endif
}
void cpu65_interrupt(int reason)
{
void cpu65_init(void) {
init_flags_conversion_tables();
run_args.cpu65__signal = 0;
run_args.cpu65_pc = 0x0;
run_args.cpu65_ea = 0x0;
run_args.cpu65_a = 0xFF;
run_args.cpu65_x = 0xFF;
run_args.cpu65_y = 0xFF;
run_args.cpu65_f = (C_Flag_6502|X_Flag_6502|I_Flag_6502|V_Flag_6502|B_Flag_6502|Z_Flag_6502|N_Flag_6502);
run_args.cpu65_sp = 0xFC;
}
void cpu65_interrupt(int reason) {
pthread_mutex_lock(&irq_mutex);
cpu65__signal |= reason;
run_args.cpu65__signal |= reason;
pthread_mutex_unlock(&irq_mutex);
}
void cpu65_uninterrupt(int reason)
{
void cpu65_uninterrupt(int reason) {
pthread_mutex_lock(&irq_mutex);
cpu65__signal &= ~reason;
run_args.cpu65__signal &= ~reason;
pthread_mutex_unlock(&irq_mutex);
}
void cpu65_reboot(void) {
joy_button0 = 0xff; // OpenApple -- should be balanced by c_joystick_reset() triggers on CPU thread
run_args.joy_button0 = 0xff; // OpenApple -- should be balanced by c_joystick_reset() triggers on CPU thread
cpu65_interrupt(ResetSig);
}
@@ -660,40 +674,33 @@ bool cpu65_saveState(StateHelper_s *helper) {
uint8_t serialized[4] = { 0 };
// save CPU state
serialized[0] = ((cpu65_pc & 0xFF00) >> 8);
serialized[1] = ((cpu65_pc & 0xFF ) >> 0);
if (!helper->save(fd, serialized, sizeof(cpu65_pc))) {
serialized[0] = ((run_args.cpu65_pc & 0xFF00) >> 8);
serialized[1] = ((run_args.cpu65_pc & 0xFF ) >> 0);
if (!helper->save(fd, serialized, sizeof(run_args.cpu65_pc))) {
break;
}
LOG("SAVE cpu65_pc = %04x", cpu65_pc);
serialized[0] = ((cpu65_ea & 0xFF00) >> 8);
serialized[1] = ((cpu65_ea & 0xFF ) >> 0);
if (!helper->save(fd, serialized, sizeof(cpu65_ea))) {
serialized[0] = ((run_args.cpu65_ea & 0xFF00) >> 8);
serialized[1] = ((run_args.cpu65_ea & 0xFF ) >> 0);
if (!helper->save(fd, serialized, sizeof(run_args.cpu65_ea))) {
break;
}
LOG("SAVE cpu65_ea = %04x", cpu65_ea);
if (!helper->save(fd, &cpu65_a, sizeof(cpu65_a))) {
if (!helper->save(fd, &run_args.cpu65_a, sizeof(run_args.cpu65_a))) {
break;
}
LOG("SAVE cpu65_a = %02x", cpu65_a);
if (!helper->save(fd, &cpu65_f, sizeof(cpu65_f))) {
if (!helper->save(fd, &run_args.cpu65_f, sizeof(run_args.cpu65_f))) {
break;
}
LOG("SAVE cpu65_f = %02x", cpu65_f);
if (!helper->save(fd, &cpu65_x, sizeof(cpu65_x))) {
if (!helper->save(fd, &run_args.cpu65_x, sizeof(run_args.cpu65_x))) {
break;
}
LOG("SAVE cpu65_x = %02x", cpu65_x);
if (!helper->save(fd, &cpu65_y, sizeof(cpu65_y))) {
if (!helper->save(fd, &run_args.cpu65_y, sizeof(run_args.cpu65_y))) {
break;
}
LOG("SAVE cpu65_y = %02x", cpu65_y);
if (!helper->save(fd, &cpu65_sp, sizeof(cpu65_sp))) {
if (!helper->save(fd, &run_args.cpu65_sp, sizeof(run_args.cpu65_sp))) {
break;
}
LOG("SAVE cpu65_sp = %02x", cpu65_sp);
saved = true;
} while (0);
@@ -713,37 +720,30 @@ bool cpu65_loadState(StateHelper_s *helper) {
if (!helper->load(fd, serialized, sizeof(uint16_t))) {
break;
}
cpu65_pc = (serialized[0] << 8);
cpu65_pc |= serialized[1];
LOG("LOAD cpu65_pc = %04x", cpu65_pc);
run_args.cpu65_pc = (serialized[0] << 8);
run_args.cpu65_pc |= serialized[1];
if (!helper->load(fd, serialized, sizeof(uint16_t))) {
break;
}
cpu65_ea = (serialized[0] << 8);
cpu65_ea |= serialized[1];
LOG("LOAD cpu65_ea = %04x", cpu65_ea);
run_args.cpu65_ea = (serialized[0] << 8);
run_args.cpu65_ea |= serialized[1];
if (!helper->load(fd, &cpu65_a, sizeof(cpu65_a))) {
if (!helper->load(fd, &run_args.cpu65_a, sizeof(run_args.cpu65_a))) {
break;
}
LOG("LOAD cpu65_a = %02x", cpu65_a);
if (!helper->load(fd, &cpu65_f, sizeof(cpu65_f))) {
if (!helper->load(fd, &run_args.cpu65_f, sizeof(run_args.cpu65_f))) {
break;
}
LOG("LOAD cpu65_f = %02x", cpu65_f);
if (!helper->load(fd, &cpu65_x, sizeof(cpu65_x))) {
if (!helper->load(fd, &run_args.cpu65_x, sizeof(run_args.cpu65_x))) {
break;
}
LOG("LOAD cpu65_x = %02x", cpu65_x);
if (!helper->load(fd, &cpu65_y, sizeof(cpu65_y))) {
if (!helper->load(fd, &run_args.cpu65_y, sizeof(run_args.cpu65_y))) {
break;
}
LOG("LOAD cpu65_y = %02x", cpu65_y);
if (!helper->load(fd, &cpu65_sp, sizeof(cpu65_sp))) {
if (!helper->load(fd, &run_args.cpu65_sp, sizeof(run_args.cpu65_sp))) {
break;
}
LOG("LOAD cpu65_sp = %02x", cpu65_sp);
loaded = true;
} while (0);
@@ -782,7 +782,7 @@ void cpu65_trace_toggle(const char *trace_file) {
GLUE_C_WRITE(cpu65_trace_prologue)
{
nargs = 0;
current_pc = cpu65_pc;
current_pc = run_args.cpu65_pc;
}
GLUE_C_WRITE(cpu65_trace_arg)
@@ -791,20 +791,6 @@ GLUE_C_WRITE(cpu65_trace_arg)
opargs[nargs++] = b;
}
GLUE_C_WRITE(cpu65_trace_arg1)
{
assert(nargs <= 2);
opargs[2] = b;
++nargs;
}
GLUE_C_WRITE(cpu65_trace_arg2)
{
assert(nargs <= 2);
opargs[1] = b;
++nargs;
}
GLUE_C_WRITE(cpu65_trace_epilogue)
{
int8_t arg1 = opargs[1];
@@ -816,14 +802,14 @@ GLUE_C_WRITE(cpu65_trace_epilogue)
assert(nargs > 0);
assert(nargs <= 3);
if (nargs != opcodes_65c02_numargs[cpu65_opcode]+1) {
if (nargs != opcodes_65c02_numargs[run_args.cpu65_opcode]+1) {
assert(false && "OOPS, most likely some cpu.S routine is not properly setting the arg value");
}
switch (opcodes_65c02[cpu65_opcode].mode) {
switch (opcodes_65c02[run_args.cpu65_opcode].mode) {
case addr_implied:
case addr_accumulator:
fprintf(cpu_trace_fp, "%04X:%02X ", current_pc, cpu65_opcode);
fprintf(cpu_trace_fp, "%04X:%02X ", current_pc, run_args.cpu65_opcode);
break;
case addr_immediate:
case addr_zeropage:
@@ -833,64 +819,73 @@ GLUE_C_WRITE(cpu65_trace_epilogue)
case addr_indirect_x:
case addr_indirect_y:
case addr_relative:
fprintf(cpu_trace_fp, "%04X:%02X%02X ", current_pc, cpu65_opcode, (uint8_t)arg1);
fprintf(cpu_trace_fp, "%04X:%02X%02X ", current_pc, run_args.cpu65_opcode, (uint8_t)arg1);
break;
case addr_absolute:
case addr_absolute_x:
case addr_absolute_y:
case addr_j_indirect:
case addr_j_indirect_x:
fprintf(cpu_trace_fp, "%04X:%02X%02X%02X", current_pc, cpu65_opcode, (uint8_t)arg2, (uint8_t)arg1);
fprintf(cpu_trace_fp, "%04X:%02X%02X%02X", current_pc, run_args.cpu65_opcode, (uint8_t)arg1, (uint8_t)arg2);
break;
default:
fprintf(cpu_trace_fp, "invalid opcode mode");
break;
}
fprintf(cpu_trace_fp, " SP:%02X X:%02X Y:%02X A:%02X", cpu65_sp, cpu65_x, cpu65_y, cpu65_a);
fprintf(cpu_trace_fp, " SP:%02X X:%02X Y:%02X A:%02X", run_args.cpu65_sp, run_args.cpu65_x, run_args.cpu65_y, run_args.cpu65_a);
#define FLAGS_BUFSZ 9
char flags_buf[FLAGS_BUFSZ];
memset(flags_buf, '-', FLAGS_BUFSZ);
if (cpu65_f & C_Flag_6502) {
if (run_args.cpu65_f & C_Flag_6502) {
flags_buf[0]='C';
}
if (cpu65_f & X_Flag_6502) {
if (run_args.cpu65_f & X_Flag_6502) {
flags_buf[1]='X';
}
if (cpu65_f & I_Flag_6502) {
if (run_args.cpu65_f & I_Flag_6502) {
flags_buf[2]='I';
}
if (cpu65_f & V_Flag_6502) {
if (run_args.cpu65_f & V_Flag_6502) {
flags_buf[3]='V';
}
if (cpu65_f & B_Flag_6502) {
if (run_args.cpu65_f & B_Flag_6502) {
flags_buf[4]='B';
}
if (cpu65_f & D_Flag_6502) {
if (run_args.cpu65_f & D_Flag_6502) {
flags_buf[5]='D';
}
if (cpu65_f & Z_Flag_6502) {
if (run_args.cpu65_f & Z_Flag_6502) {
flags_buf[6]='Z';
}
if (cpu65_f & N_Flag_6502) {
if (run_args.cpu65_f & N_Flag_6502) {
flags_buf[7]='N';
}
flags_buf[8] = '\0';
char fmt[64];
if (UNLIKELY(cpu65_opcycles >= 10)) {
if (UNLIKELY(run_args.cpu65_opcycles >= 10)) {
// occurs rarely for interrupt + opcode
snprintf(fmt, 64, "%s", " %s CY:%u irqChk:%d totCyc:%d EA:%04X");
snprintf(fmt, 64, "%s", " %s CY:%u");
} else {
snprintf(fmt, 64, "%s", " %s CYC:%u irqChk:%d totCyc:%d EA:%04X");
snprintf(fmt, 64, "%s", " %s CYC:%u");
}
extern int32_t irqCheckTimeout;
fprintf(cpu_trace_fp, fmt, flags_buf, cpu65_opcycles, (irqCheckTimeout - cpu65_opcycles), (cycles_count_total + cpu65_opcycles), cpu65_ea);
fprintf(cpu_trace_fp, fmt, flags_buf, run_args.cpu65_opcycles);
sprintf(fmt, " %s %s", opcodes_65c02[cpu65_opcode].mnemonic, disasm_templates[opcodes_65c02[cpu65_opcode].mode]);
uint16_t vidAddr = video_scannerAddress(NULL);
uint8_t vidData = apple_ii_64k[0][vidAddr];
fprintf(cpu_trace_fp, " VID:%04X:%02X", vidAddr, vidData);
switch (opcodes_65c02[cpu65_opcode].mode) {
#if CPU_TRACING_SHOW_EA
fprintf(cpu_trace_fp, " EA:%04X", run_args.cpu65_ea);
#endif
fprintf(cpu_trace_fp, " CY+%lu", (cycles_count_total + run_args.cpu65_opcycles));
sprintf(fmt, " %s %s", opcodes_65c02[run_args.cpu65_opcode].mnemonic, disasm_templates[opcodes_65c02[run_args.cpu65_opcode].mode]);
switch (opcodes_65c02[run_args.cpu65_opcode].mode) {
case addr_implied:
case addr_accumulator:
fprintf(cpu_trace_fp, "%s", fmt);
@@ -909,7 +904,7 @@ GLUE_C_WRITE(cpu65_trace_epilogue)
case addr_absolute_y:
case addr_j_indirect:
case addr_j_indirect_x:
fprintf(cpu_trace_fp, fmt, (uint8_t)arg1, (uint8_t)arg2);
fprintf(cpu_trace_fp, fmt, (uint8_t)arg2, (uint8_t)arg1);
break;
case addr_relative:
if (arg1 < 0) {
@@ -928,7 +923,7 @@ GLUE_C_WRITE(cpu65_trace_epilogue)
GLUE_C_WRITE(cpu65_trace_irq)
{
if (cpu_trace_fp) {
fprintf(cpu_trace_fp, "IRQ:%02X\n", cpu65__signal);
fprintf(cpu_trace_fp, "IRQ:%02X\n", run_args.cpu65__signal);
}
}

View File

@@ -23,32 +23,23 @@
#include <sys/types.h>
#include <stdint.h>
#include "glue.h"
/* types */
#define MEM_READ_FLAG (1<<0)
#define MEM_WRITE_FLAG (1<<1)
extern uint16_t cpu65_pc; // Program counter
extern uint8_t cpu65_a; // Accumulator
extern uint8_t cpu65_f; // Flags (host-order)
extern uint8_t cpu65_x; // X Index register
extern uint8_t cpu65_y; // Y Index register
extern uint8_t cpu65_sp; // Stack Pointer
extern uint16_t cpu65_ea; // Last effective address
extern uint8_t cpu65_d; // Last data byte written
extern uint8_t cpu65_rw; // MEM_READ_FLAG = read occured, MEM_WRITE_FLAG = write
extern uint8_t cpu65_opcode; // Last opcode
extern uint8_t cpu65_opcycles; // Last opcode extra cycles
extern cpu65_run_args_s run_args;
/* Set up the processor for a new run. Sets up opcode table. */
extern void cpu65_init();
extern void cpu65_init(void);
/* Interrupt the processor */
extern void cpu65_interrupt(int reason);
extern void cpu65_uninterrupt(int reason);
extern void cpu65_run(void);
extern void cpu65_run(void *args);
extern void cpu65_reboot(void);
extern bool cpu65_saveState(StateHelper_s *helper);
@@ -59,10 +50,8 @@ extern void cpu65_direct_write(int ea,int data);
extern void *cpu65_vmem_r[65536];
extern void *cpu65_vmem_w[65536];
extern unsigned char cpu65_flags_encode[256];
extern unsigned char cpu65_flags_decode[256];
extern int32_t cpu65_cycle_count;
extern uint8_t cpu65_flags_encode[256];
extern uint8_t cpu65_flags_decode[256];
#if CPU_TRACING
void cpu65_trace_begin(const char *trace_file);
@@ -73,8 +62,6 @@ void cpu65_trace_checkpoint(void);
#endif /* !__ASSEMBLER__ */
#define IRQ_CHECK_CYCLES 128
#define ResetSig 0x02
#define IRQ6522 0x08
#define IRQSpeech 0x10

Some files were not shown because too many files have changed in this diff Show More